diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index e3a1022..31f25cf 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -257,7 +257,7 @@ namespace AssetStudio } } - public float bytesToFloat(byte[] inputBytes) + private float BytesToFloat(byte[] inputBytes) { float result = 0; if (reader.endian == EndianType.BigEndian) { Array.Reverse(inputBytes); } @@ -278,7 +278,7 @@ namespace AssetStudio return result; } - public uint[] UnpackBitVector(PackedBitVector pakData) + private static uint[] UnpackBitVector(PackedBitVector pakData) { uint[] unpackedVectors = new uint[pakData.m_NumItems]; //int bitmax = 0;//used to convert int value to float @@ -417,6 +417,69 @@ namespace AssetStudio return unpackedVectors; } + private static int GetChannelFormatLength(int format) + { + switch (format) + { + case 0: //float + return 4; + case 1: //half float + return 2; + case 2: //byte float + return 1; + case 11: //int + return 4; + default: + return 0; + } + } + + private static float[] BytesToFloatArray(byte[] inputBytes, int size) + { + var result = new float[inputBytes.Length / size]; + for (int i = 0; i < inputBytes.Length / size; i++) + { + float value = 0f; + switch (size) + { + case 1: + value = inputBytes[i] / 255.0f; + break; + case 2: + value = System.Half.ToHalf(inputBytes, i * 2); + break; + case 4: + value = BitConverter.ToSingle(inputBytes, i * 4); + break; + } + result[i] = value; + } + return result; + } + + private static int[] BytesToIntArray(byte[] inputBytes) + { + var result = new int[inputBytes.Length / 4]; + for (int i = 0; i < inputBytes.Length / 4; i++) + { + result[i] = BitConverter.ToInt32(inputBytes, i * 4); + } + return result; + } + + private void InitMSkin() + { + m_Skin = new List[m_VertexCount]; + for (int i = 0; i < m_VertexCount; i++) + { + m_Skin[i] = new List(4); + for (int j = 0; j < 4; j++) + { + m_Skin[i].Add(new BoneInfluence()); + } + } + } + public Mesh(AssetPreloadData preloadData, bool readSwitch) { var version = preloadData.sourceFile.version; @@ -653,7 +716,7 @@ namespace AssetStudio m_Skin[s] = new List(); for (int i = 0; i < 4; i++) { - m_Skin[s].Add(new BoneInfluence() {weight = reader.ReadSingle()}); + m_Skin[s].Add(new BoneInfluence() { weight = reader.ReadSingle() }); } for (int i = 0; i < 4; i++) @@ -738,7 +801,7 @@ namespace AssetStudio for (int s = 0; s < m_Streams.Length; s++) { m_Streams[s] = new StreamInfo(); - m_Streams[s].channelMask = new BitArray(new int[1] { reader.ReadInt32() }); + m_Streams[s].channelMask = new BitArray(new[] { reader.ReadInt32() }); m_Streams[s].offset = reader.ReadInt32(); m_Streams[s].stride = reader.ReadByte(); m_Streams[s].dividerOp = reader.ReadByte(); @@ -747,59 +810,47 @@ namespace AssetStudio } } #endregion - //actual Vertex Buffer - byte[] m_DataSize = new byte[reader.ReadInt32()]; - reader.Read(m_DataSize, 0, m_DataSize.Length); - - if (version[0] >= 5) //create streams + if (version[0] >= 5) //ComputeCompressedStreams { m_Streams = new StreamInfo[streamCount]; - for (int s = 0; s < streamCount; s++) + int offset = 0; + for (int str = 0; str < streamCount; str++) { - m_Streams[s] = new StreamInfo(); - m_Streams[s].offset = 0; - m_Streams[s].stride = 0; - - uint chnMask = 0; - for (var chn = 0; chn < m_Channels.Length; chn++) + int chnMask = 0; + int stride = 0; + for (int chn = 0; chn < m_Channels.Length; chn++) { var m_Channel = m_Channels[chn]; - if (m_Channel.stream == s) + if (m_Channel.stream == str) { if (m_Channel.dimension > 0) { - chnMask |= 1u << chn; + chnMask |= 1 << chn; + stride += m_Channel.dimension * GetChannelFormatLength(m_Channel.format); } - m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); } } - - if (s > 0) + m_Streams[str] = new StreamInfo { - m_Streams[s].offset = m_Streams[s - 1].offset + m_Streams[s - 1].stride * m_VertexCount; - //sometimes there are 8 bytes between streams - //this is NOT an alignment, even if sometimes it may seem so - - if (streamCount >= 2) - { - m_Streams[s].offset = m_DataSize.Length - m_Streams[s].stride * m_VertexCount; - } - - /*var absoluteOffset = a_Stream.Position + 4 + m_Streams[s].offset; - if ((absoluteOffset % m_Streams[s].stride) != 0) - { - m_Streams[s].offset += m_Streams[s].stride - (int)(absoluteOffset % m_Streams[s].stride); - }*/ - } - m_Streams[s].channelMask = new BitArray(new[] { (int)chnMask }); + channelMask = new BitArray(new[] { chnMask }), + offset = offset, + stride = stride, + dividerOp = 0, + frequency = 0 + }; + offset += m_VertexCount * stride + ((m_VertexCount & 1) != 0 ? 8 : 0); } } + + //actual Vertex Buffer + byte[] m_DataSize = new byte[reader.ReadInt32()]; + reader.Read(m_DataSize, 0, m_DataSize.Length); #endregion #region compute FvF int componentByteSize = 0; byte[] componentBytes; - float[] componentsArray; + float[] componentsArray = null; #region 4.0.0 and later if (m_Channels != null) @@ -812,7 +863,7 @@ namespace AssetStudio { var m_Stream = m_Streams[m_Channel.stream]; - for (int b = 0; b < 8; b++) + for (int b = 0; b < 32; b++) { if (m_Stream.channelMask.Get(b)) { @@ -822,24 +873,9 @@ namespace AssetStudio m_Channel.dimension = 4; } - componentByteSize = 4 / (int)Math.Pow(2, m_Channel.format); - - /*switch (m_Channel.format) - { - case 0: //32bit - valueBufferSize = 4; - break; - case 1: //16bit - valueBufferSize = 2; - break; - case 2: //8bit - valueBufferSize = 1; - m_Channel.dimension = 4;//in older versions this is 1, as in 1 color with 4 components - break; - }*/ - - componentBytes = new byte[componentByteSize]; - componentsArray = new float[m_VertexCount * m_Channel.dimension]; + int[] componentsIntArray = null; + componentByteSize = GetChannelFormatLength(m_Channel.format); + componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize]; for (int v = 0; v < m_VertexCount; v++) { @@ -847,24 +883,71 @@ namespace AssetStudio for (int d = 0; d < m_Channel.dimension; d++) { int componentOffset = vertexOffset + componentByteSize * d; - Buffer.BlockCopy(m_DataSize, componentOffset, componentBytes, 0, componentByteSize); - componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); + Buffer.BlockCopy(m_DataSize, componentOffset, componentBytes, componentByteSize * (v * m_Channel.dimension + d), componentByteSize); } } + if (m_Channel.format == 11) + componentsIntArray = BytesToIntArray(componentBytes); + else + componentsArray = BytesToFloatArray(componentBytes, componentByteSize); + switch (b) { - case 0: m_Vertices = componentsArray; break; - case 1: m_Normals = componentsArray; break; - case 2: m_Colors = componentsArray; break; - case 3: m_UV1 = componentsArray; break; - case 4: m_UV2 = componentsArray; break; - case 5: - if (version[0] >= 5) { m_UV3 = componentsArray; } - else { m_Tangents = componentsArray; } + case 0: + m_Vertices = componentsArray; + break; + case 1: + m_Normals = componentsArray; + break; + case 2: + m_Colors = componentsArray; + break; + case 3: + m_UV1 = componentsArray; + break; + case 4: + m_UV2 = componentsArray; + break; + case 5: + if (version[0] >= 5) + { + m_UV3 = componentsArray; + } + else + { + m_Tangents = componentsArray; + } + break; + case 6: + m_UV4 = componentsArray; + break; + case 7: + m_Tangents = componentsArray; + break; + //2018.2 and up + case 12: + if (m_Skin == null) + InitMSkin(); + for (int i = 0; i < m_VertexCount; i++) + { + for (int j = 0; j < 4; j++) + { + m_Skin[i][j].weight = componentsArray[i * 4 + j]; + } + } + break; + case 13: + if (m_Skin == null) + InitMSkin(); + for (int i = 0; i < m_VertexCount; i++) + { + for (int j = 0; j < 4; j++) + { + m_Skin[i][j].boneIndex = componentsIntArray[i * 4 + j]; + } + } break; - case 6: m_UV4 = componentsArray; break; - case 7: m_Tangents = componentsArray; break; } m_Stream.channelMask.Set(b, false); @@ -922,7 +1005,7 @@ namespace AssetStudio { int m_DataSizeOffset = vertexOffset + componentByteSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, componentBytes, 0, componentByteSize); - componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); + componentsArray[v * m_Channel.dimension + d] = BytesToFloat(componentBytes); } }