public Texture2D(AssetPreloadData preloadData, bool readSwitch) { AssetsFile sourceFile = preloadData.sourceFile; EndianStream stream = preloadData.sourceFile.a_Stream; stream.Position = preloadData.Offset; if (sourceFile.platform == -2) { uint num = stream.ReadUInt32(); PPtr ptr = sourceFile.ReadPPtr(); PPtr ptr2 = sourceFile.ReadPPtr(); } this.m_Name = stream.ReadAlignedString(stream.ReadInt32()); this.m_Width = stream.ReadInt32(); this.m_Height = stream.ReadInt32(); this.m_CompleteImageSize = stream.ReadInt32(); this.m_TextureFormat = stream.ReadInt32(); this.getExtension(preloadData, this.m_TextureFormat); if (this.m_Name != "") { preloadData.Name = this.m_Name; } else { preloadData.Name = preloadData.TypeString + " #" + preloadData.uniqueID; } if ((sourceFile.version[0] < 5) || ((sourceFile.version[0] == 5) && (sourceFile.version[1] < 2))) { this.m_MipMap = stream.ReadBoolean(); } else { this.dwFlags += 0x20000; this.dwMipMapCount = stream.ReadInt32(); this.dwCaps += 0x400008; } this.m_IsReadable = stream.ReadBoolean(); this.m_ReadAllowed = stream.ReadBoolean(); stream.AlignStream(4); this.m_ImageCount = stream.ReadInt32(); this.m_TextureDimension = stream.ReadInt32(); this.m_FilterMode = stream.ReadInt32(); this.m_Aniso = stream.ReadInt32(); this.m_MipBias = stream.ReadSingle(); this.m_WrapMode = stream.ReadInt32(); if (sourceFile.version[0] >= 3) { this.m_LightmapFormat = stream.ReadInt32(); if ((sourceFile.version[0] >= 4) || (sourceFile.version[1] >= 5)) { this.m_ColorSpace = stream.ReadInt32(); } } this.image_data_size = stream.ReadInt32(); if (this.m_MipMap) { this.dwFlags += 0x20000; this.dwMipMapCount = Convert.ToInt32((double)(Math.Log((double)Math.Max(this.m_Width, this.m_Height)) / Math.Log(2.0))); this.dwCaps += 0x400008; } if (!readSwitch) { string[] textArray1 = new string[] { "Width: ", this.m_Width.ToString(), "\nHeight: ", this.m_Height.ToString(), "\nFormat: " }; preloadData.InfoText = string.Concat(textArray1); preloadData.exportSize = this.image_data_size; switch (this.m_TextureFormat) { case 1: preloadData.InfoText = preloadData.InfoText + "Alpha8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 2: preloadData.InfoText = preloadData.InfoText + "ARGB 4.4.4.4"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 3: preloadData.InfoText = preloadData.InfoText + "BGR 8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 4: preloadData.InfoText = preloadData.InfoText + "GRAB 8.8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 5: preloadData.InfoText = preloadData.InfoText + "BGRA 8.8.8.8"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 7: preloadData.InfoText = preloadData.InfoText + "RGB 5.6.5"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 10: preloadData.InfoText = preloadData.InfoText + "DXT1"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 12: preloadData.InfoText = preloadData.InfoText + "DXT5"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 13: preloadData.InfoText = preloadData.InfoText + "RGBA 4.4.4.4"; preloadData.extension = ".dds"; preloadData.exportSize += 0x80; goto Label_0E7B; case 0x1c: preloadData.InfoText = preloadData.InfoText + "DXT1 Crunched"; preloadData.extension = ".crn"; goto Label_0E7B; case 0x1d: preloadData.InfoText = preloadData.InfoText + "DXT5 Crunched"; preloadData.extension = ".crn"; goto Label_0E7B; case 30: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGB2"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x1f: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGBA2"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x20: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGB4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x21: preloadData.InfoText = preloadData.InfoText + "PVRTC_RGBA4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; case 0x22: preloadData.InfoText = preloadData.InfoText + "ETC_RGB4"; preloadData.extension = ".pvr"; preloadData.exportSize += 0x34; goto Label_0E7B; } preloadData.InfoText = preloadData.InfoText + "unknown"; preloadData.extension = ".tex"; } else { this.image_data = new byte[this.image_data_size]; stream.Read(this.image_data, 0, this.image_data_size); switch (this.m_TextureFormat) { case 1: this.dwFlags2 = 2; this.dwRGBBitCount = 8; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0xff; return; case 2: if (sourceFile.platform != 11) { if (sourceFile.platform == 13) { for (int j = 0; j < (this.image_data_size / 2); j++) { byte[] buffer1 = new byte[] { this.image_data[j * 2], this.image_data[(j * 2) + 1], this.image_data[j * 2], this.image_data[(j * 2) + 1] }; byte[] bytes = BitConverter.GetBytes((int)(BitConverter.ToInt32(buffer1, 0) >> 4)); this.image_data[j * 2] = bytes[0]; this.image_data[(j * 2) + 1] = bytes[1]; } } break; } for (int i = 0; i < (this.image_data_size / 2); i++) { byte num4 = this.image_data[i * 2]; this.image_data[i * 2] = this.image_data[(i * 2) + 1]; this.image_data[(i * 2) + 1] = num4; } break; case 3: for (int k = 0; k < (this.image_data_size / 3); k++) { byte num7 = this.image_data[k * 3]; this.image_data[k * 3] = this.image_data[(k * 3) + 2]; this.image_data[(k * 3) + 2] = num7; } this.dwFlags2 = 0x40; this.dwRGBBitCount = 0x18; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = 0; return; case 4: for (int m = 0; m < (this.image_data_size / 4); m++) { byte num9 = this.image_data[m * 4]; this.image_data[m * 4] = this.image_data[(m * 4) + 2]; this.image_data[(m * 4) + 2] = num9; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x20; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = -16777216; return; case 5: for (int n = 0; n < (this.image_data_size / 4); n++) { byte num11 = this.image_data[n * 4]; byte num12 = this.image_data[(n * 4) + 1]; this.image_data[n * 4] = this.image_data[(n * 4) + 3]; this.image_data[(n * 4) + 1] = this.image_data[(n * 4) + 2]; this.image_data[(n * 4) + 2] = num12; this.image_data[(n * 4) + 3] = num11; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x20; this.dwRBitMask = 0xff0000; this.dwGBitMask = 0xff00; this.dwBBitMask = 0xff; this.dwABitMask = -16777216; return; case 6: case 8: case 9: case 11: case 0x1c: case 0x1d: return; case 7: if (sourceFile.platform == 11) { for (int num13 = 0; num13 < (this.image_data_size / 2); num13++) { byte num14 = this.image_data[num13 * 2]; this.image_data[num13 * 2] = this.image_data[(num13 * 2) + 1]; this.image_data[(num13 * 2) + 1] = num14; } } this.dwFlags2 = 0x40; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf800; this.dwGBitMask = 0x7e0; this.dwBBitMask = 0x1f; this.dwABitMask = 0; return; case 10: if (sourceFile.platform == 11) { for (int num15 = 0; num15 < (this.image_data_size / 2); num15++) { byte num16 = this.image_data[num15 * 2]; this.image_data[num15 * 2] = this.image_data[(num15 * 2) + 1]; this.image_data[(num15 * 2) + 1] = num16; } } if (this.m_MipMap) { this.dwPitchOrLinearSize = (this.m_Height * this.m_Width) / 2; } this.dwFlags2 = 4; this.dwFourCC = 0x31545844; this.dwRGBBitCount = 0; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0; return; case 12: if (sourceFile.platform == 11) { for (int num17 = 0; num17 < (this.image_data_size / 2); num17++) { byte num18 = this.image_data[num17 * 2]; this.image_data[num17 * 2] = this.image_data[(num17 * 2) + 1]; this.image_data[(num17 * 2) + 1] = num18; } } if (this.m_MipMap) { this.dwPitchOrLinearSize = (this.m_Height * this.m_Width) / 2; } this.dwFlags2 = 4; this.dwFourCC = 0x35545844; this.dwRGBBitCount = 0; this.dwRBitMask = 0; this.dwGBitMask = 0; this.dwBBitMask = 0; this.dwABitMask = 0; return; case 13: for (int num19 = 0; num19 < (this.image_data_size / 2); num19++) { byte[] buffer3 = new byte[] { this.image_data[num19 * 2], this.image_data[(num19 * 2) + 1], this.image_data[num19 * 2], this.image_data[(num19 * 2) + 1] }; byte[] buffer2 = BitConverter.GetBytes((int)(BitConverter.ToInt32(buffer3, 0) >> 4)); this.image_data[num19 * 2] = buffer2[0]; this.image_data[(num19 * 2) + 1] = buffer2[1]; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf00; this.dwGBitMask = 240; this.dwBBitMask = 15; this.dwABitMask = 0xf000; return; case 30: this.pvrPixelFormat = 0L; return; case 0x1f: this.pvrPixelFormat = 1L; return; case 0x20: this.pvrPixelFormat = 2L; return; case 0x21: this.pvrPixelFormat = 3L; return; case 0x22: this.pvrPixelFormat = 0x16L; return; default: return; } this.dwFlags2 = 0x41; this.dwRGBBitCount = 0x10; this.dwRBitMask = 0xf00; this.dwGBitMask = 240; this.dwBBitMask = 15; this.dwABitMask = 0xf000; return; } Label_0E7B: switch (this.m_FilterMode) { case 0: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Point "; break; case 1: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Bilinear "; break; case 2: preloadData.InfoText = preloadData.InfoText + "\nFilter Mode: Trilinear "; break; } AssetPreloadData data = preloadData; string[] textArray2 = new string[] { data.InfoText, "\nAnisotropic level: ", this.m_Aniso.ToString(), "\nMip map bias: ", this.m_MipBias.ToString() }; data.InfoText = string.Concat(textArray2); switch (this.m_WrapMode) { case 0: preloadData.InfoText = preloadData.InfoText + "\nWrap mode: Repeat"; break; case 1: preloadData.InfoText = preloadData.InfoText + "\nWrap mode: Clamp"; break; } }
public Mesh(AssetPreloadData MeshPD) { //Stream = new EndianStream(File.OpenRead(sourceFile.filePath), sourceFile.endianType); //Stream.endian = sourceFile.endianType; var version = MeshPD.sourceFile.version; a_Stream = MeshPD.sourceFile.a_Stream; a_Stream.Position = MeshPD.Offset; bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices uint m_MeshCompression = 0; if (MeshPD.sourceFile.platform == -2) { uint m_ObjectHideFlags = a_Stream.ReadUInt32(); PPtr m_PrefabParentObject = MeshPD.sourceFile.ReadPPtr(); PPtr m_PrefabInternal = MeshPD.sourceFile.ReadPPtr(); } m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_Use16BitIndices = a_Stream.ReadBoolean(); a_Stream.Position += 3; } #region Index Buffer for 2.5.1 and earlier if (version[0] == 2 && version[1] <= 5) { int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } } } #endregion #region subMeshes int m_SubMeshes_size = a_Stream.ReadInt32(); for (int s = 0; s < m_SubMeshes_size; s++) { m_SubMeshes.Add(new SubMesh()); m_SubMeshes[s].firstByte = a_Stream.ReadUInt32(); m_SubMeshes[s].indexCount = a_Stream.ReadUInt32(); //what is this in case of triangle strips? m_SubMeshes[s].topology = a_Stream.ReadInt32(); //isTriStrip if (version[0] < 4) { m_SubMeshes[s].triangleCount = a_Stream.ReadUInt32(); } if (version[0] >= 3) { m_SubMeshes[s].firstVertex = a_Stream.ReadUInt32(); m_SubMeshes[s].vertexCount = a_Stream.ReadUInt32(); a_Stream.Position += 24; //Axis-Aligned Bounding Box } } #endregion #region BlendShapeData for 4.1.0 to 4.2.x, excluding 4.1.0 alpha if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") || (version[1] > 1 && version[1] <= 2))) { int m_Shapes_size = a_Stream.ReadInt32(); if (m_Shapes_size > 0) { bool stop = true; } for (int s = 0; s < m_Shapes_size; s++) //untested { string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents } int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } #endregion #region BlendShapeData and BindPose for 4.3.0 and later else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3)) { int m_ShapeVertices_size = a_Stream.ReadInt32(); if (m_ShapeVertices_size > 0) { bool stop = true; } a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index int shapes_size = a_Stream.ReadInt32(); a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents int channels_size = a_Stream.ReadInt32(); for (int c = 0; c < channels_size; c++) { string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount } int fullWeights_size = a_Stream.ReadInt32(); a_Stream.Position += fullWeights_size * 4; //floats m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4,4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } int m_BoneNameHashes_size = a_Stream.ReadInt32(); a_Stream.Position += m_BoneNameHashes_size * 4; //uints uint m_RootBoneNameHash = a_Stream.ReadUInt32(); } #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { m_MeshCompression = a_Stream.ReadByte(); if (version[0] >= 4) { if (version[0] < 5) { uint m_StreamCompression = a_Stream.ReadByte(); } bool m_IsReadable = a_Stream.ReadBoolean(); bool m_KeepVertices = a_Stream.ReadBoolean(); bool m_KeepIndices = a_Stream.ReadBoolean(); } a_Stream.AlignStream(4); int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } a_Stream.AlignStream(4);//untested } } #endregion #region Vertex Buffer for 3.4.2 and earlier if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_VertexCount = a_Stream.ReadInt32(); m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } m_Skin = new List<BoneInfluence>[a_Stream.ReadInt32()]; //m_Skin = new Dictionary<int, float>[a_Stream.ReadInt32()]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } /*m_Skin[s] = new Dictionary<int, float>(); float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; for (int i = 0; i < 4; i++) { int boneIndex = a_Stream.ReadInt32(); m_Skin[s][boneIndex] = weights[i]; }*/ } m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } int m_UV1_size = a_Stream.ReadInt32(); m_UV1 = new float[m_UV1_size * 2]; for (int v = 0; v < m_UV1_size * 2; v++) { m_UV1[v] = a_Stream.ReadSingle(); } int m_UV2_size = a_Stream.ReadInt32(); m_UV2 = new float[m_UV2_size * 2]; for (int v = 0; v < m_UV2_size * 2; v++) { m_UV2[v] = a_Stream.ReadSingle(); } if (version[0] == 2 && version[1] <= 5) { int m_TangentSpace_size = a_Stream.ReadInt32(); m_Normals = new float[m_TangentSpace_size * 3]; for (int v = 0; v < m_TangentSpace_size; v++) { m_Normals[v * 3] = a_Stream.ReadSingle(); m_Normals[v * 3 + 1] = a_Stream.ReadSingle(); m_Normals[v * 3 + 2] = a_Stream.ReadSingle(); a_Stream.Position += 16; //Vector3f tangent & float handedness } } else //2.6.0 and later { int m_Tangents_size = a_Stream.ReadInt32(); a_Stream.Position += m_Tangents_size * 16; //Vector4f int m_Normals_size = a_Stream.ReadInt32(); m_Normals = new float[m_Normals_size * 3]; for (int v = 0; v < m_Normals_size * 3; v++) { m_Normals[v] = a_Stream.ReadSingle(); } } } #endregion #region Vertex Buffer for 3.5.0 and later else { #region read vertex stream m_Skin = new List<BoneInfluence>[a_Stream.ReadInt32()]; //m_Skin = new Dictionary<int, float>[a_Stream.ReadInt32()]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } /*m_Skin[s] = new Dictionary<int, float>(); float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; for (int i = 0; i < 4; i++) { int boneIndex = a_Stream.ReadInt32(); m_Skin[s][boneIndex] = weights[i]; }*/ } if (version[0] == 3 || (version[0] == 4 && version[1] <= 2)) { m_BindPose = new float[a_Stream.ReadInt32()][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4] { { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; } } BitArray m_CurrentChannels = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_VertexCount = a_Stream.ReadInt32(); //int singleStreamStride = 0;//used tor unity 5 int streamCount = 0; #region streams for 3.5.0 - 3.5.7 if (version[0] < 4) { if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 { a_Stream.Position += 12; } else { m_Streams = new StreamInfo[4]; for (int s = 0; s < 4; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadInt32(); m_Streams[s].align = a_Stream.ReadUInt32(); } } } #endregion #region channels and streams for 4.0.0 and later else { m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; for (int c = 0; c < m_Channels.Length; c++) { m_Channels[c] = new ChannelInfo(); m_Channels[c].stream = a_Stream.ReadByte(); m_Channels[c].offset = a_Stream.ReadByte(); m_Channels[c].format = a_Stream.ReadByte(); m_Channels[c].dimension = a_Stream.ReadByte(); //calculate stride for Unity 5 //singleStreamStride += m_Channels[c].dimension * (4 / (int)Math.Pow(2, m_Channels[c].format)); if (m_Channels[c].stream >= streamCount) { streamCount = m_Channels[c].stream + 1; } } if (version[0] < 5) { m_Streams = new StreamInfo[a_Stream.ReadInt32()]; for (int s = 0; s < m_Streams.Length; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadByte(); m_Streams[s].dividerOp = a_Stream.ReadByte(); m_Streams[s].frequency = a_Stream.ReadUInt16(); } } } #endregion //actual Vertex Buffer byte[] m_DataSize = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_DataSize, 0, m_DataSize.Length); if (version[0] >= 5) //create streams { m_Streams = new StreamInfo[streamCount]; for (int s = 0; s < streamCount; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { 0 }); m_Streams[s].offset = 0; m_Streams[s].stride = 0; foreach (var m_Channel in m_Channels) { if (m_Channel.stream == s) { m_Streams[s].stride += m_Channel.dimension * (4 / (int)Math.Pow(2, m_Channel.format)); } } if (s > 0) { 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; } else { m_VertexCount = 0; return; } /*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); }*/ } } } #endregion #region compute FvF int componentByteSize = 0; byte[] componentBytes; float[] componentsArray; #region 4.0.0 and later if (m_Channels != null) { //it is better to loop channels instead of streams //because channels are likely to be sorted by vertex property foreach (var m_Channel in m_Channels) { if (m_Channel.dimension > 0) { var m_Stream = m_Streams[m_Channel.stream]; for (int b = 0; b < 8; b++) { //in the future, try to use only m_CurrentChannels if ((version[0] < 5 && m_Stream.channelMask.Get(b)) || (version[0] >= 5 && m_CurrentChannels.Get(b))) { // in Unity 4.x the colors channel has 1 dimension, as in 1 color with 4 components if (b == 2 && m_Channel.format == 2) { 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]; for (int v = 0; v < m_VertexCount; v++) { int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; 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); } } 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; } break; case 6: m_UV4 = componentsArray; break; case 7: m_Tangents = componentsArray; break; } m_Stream.channelMask.Set(b, false); m_CurrentChannels.Set(b, false); componentBytes = null; componentsArray = null; break; //go to next channel } } } } } #endregion #region 3.5.0 - 3.5.7 else if (m_Streams != null) { foreach (var m_Stream in m_Streams) { //a stream may have multiple vertex components but without channels there are no offsets, so I assume all vertex properties are in order //Unity 3.5.x only uses floats, and that's probably why channels were introduced in Unity 4 ChannelInfo m_Channel = new ChannelInfo();//create my own channel so I can use the same methods m_Channel.offset = 0; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { switch (b) { case 0: case 1: componentByteSize = 4; m_Channel.dimension = 3; break; case 2: componentByteSize = 1; m_Channel.dimension = 4; break; case 3: case 4: componentByteSize = 4; m_Channel.dimension = 2; break; case 5: componentByteSize = 4; m_Channel.dimension = 4; break; } componentBytes = new byte[componentByteSize]; componentsArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = vertexOffset + componentByteSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, componentBytes, 0, componentByteSize); componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); } } 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: m_Tangents = componentsArray; break; } m_Channel.offset += (byte)(m_Channel.dimension * componentByteSize); //safe to cast as byte because strides larger than 255 are unlikely m_Stream.channelMask.Set(b, false); componentBytes = null; componentsArray = null; } } } } #endregion #endregion } #endregion #region Compressed Mesh data for 2.6.0 and later - 160 bytes if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { //remember there can be combinations of packed and regular vertex properties #region m_Vertices PackedBitVector m_Vertices_Packed = new PackedBitVector(); m_Vertices_Packed.m_NumItems = a_Stream.ReadInt32(); m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Vertices_Packed.m_Data, 0, m_Vertices_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Vertices_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Vertices_Packed.m_NumItems > 0) { m_VertexCount = m_Vertices_Packed.m_NumItems / 3; uint[] m_Vertices_Unpacked = UnpackBitVector(m_Vertices_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Vertices = new float[m_Vertices_Packed.m_NumItems]; for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) { m_Vertices[v] = (float)((double)m_Vertices_Unpacked[v] / bitmax) * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; } } #endregion #region m_UV PackedBitVector m_UV_Packed = new PackedBitVector(); //contains all channels m_UV_Packed.m_NumItems = a_Stream.ReadInt32(); m_UV_Packed.m_Range = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_UV_Packed.m_Data, 0, m_UV_Packed.m_Data.Length); a_Stream.AlignStream(4); m_UV_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_UV_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportUVs"]) { uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); int bitmax = 0; for (int b = 0; b < m_UV_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_UV1 = new float[m_VertexCount * 2]; for (int v = 0; v < m_VertexCount * 2; v++) { m_UV1[v] = (float)((double)m_UV_Unpacked[v] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 4) { m_UV2 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV2[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems >= m_VertexCount * 6) { m_UV3 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV3[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 4] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems == m_VertexCount * 8) { m_UV4 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV4[v] = (float)((double)m_UV_Unpacked[v + m_VertexCount * 6] / bitmax) * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } } } } } #endregion #region m_BindPose if (version[0] < 5) { PackedBitVector m_BindPoses_Packed = new PackedBitVector(); m_BindPoses_Packed.m_NumItems = a_Stream.ReadInt32(); m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BindPoses_Packed.m_Data, 0, m_BindPoses_Packed.m_Data.Length); a_Stream.AlignStream(4); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_BindPoses_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportDeformers"]) { uint[] m_BindPoses_Unpacked = UnpackBitVector(m_BindPoses_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_BindPoses_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_BindPose = new float[m_BindPoses_Packed.m_NumItems / 16][,]; for (int i = 0; i < m_BindPose.Length; i++) { m_BindPose[i] = new float[4, 4]; for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { m_BindPose[i][j,k] = (float)((double)m_BindPoses_Unpacked[i * 16 + j * 4 + k] / bitmax) * m_BindPoses_Packed.m_Range + m_BindPoses_Packed.m_Start; } } } } } #endregion PackedBitVector m_Normals_Packed = new PackedBitVector(); m_Normals_Packed.m_NumItems = a_Stream.ReadInt32(); m_Normals_Packed.m_Range = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Normals_Packed.m_Data, 0, m_Normals_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Normals_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Tangents_Packed = new PackedBitVector(); m_Tangents_Packed.m_NumItems = a_Stream.ReadInt32(); m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Tangents_Packed.m_Data, 0, m_Tangents_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Weights = new PackedBitVector(); m_Weights.m_NumItems = a_Stream.ReadInt32(); m_Weights.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Weights.m_Data, 0, m_Weights.m_Data.Length); a_Stream.AlignStream(4); m_Weights.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment #region m_Normals PackedBitVector m_NormalSigns_packed = new PackedBitVector(); m_NormalSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Normals_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportNormals"]) { uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); int bitmax = 0; for (int b = 0; b < m_Normals_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Normals = new float[m_Normals_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Normals_Packed.m_NumItems / 2; v++) { m_Normals[v * 3] = (float)((double)m_Normals_Unpacked[v * 2] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 1] = (float)((double)m_Normals_Unpacked[v * 2 + 1] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 2] = (float)Math.Sqrt(1 - m_Normals[v * 3] * m_Normals[v * 3] - m_Normals[v * 3 + 1] * m_Normals[v * 3 + 1]); if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } } } #endregion #region m_Tangents PackedBitVector m_TangentSigns_packed = new PackedBitVector(); m_TangentSigns_packed.m_NumItems = a_Stream.ReadInt32(); m_TangentSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_TangentSigns_packed.m_Data, 0, m_TangentSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_TangentSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Tangents_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportTangents"]) { uint[] m_Tangents_Unpacked = UnpackBitVector(m_Tangents_Packed); uint[] m_TangentSigns = UnpackBitVector(m_TangentSigns_packed); int bitmax = 0; for (int b = 0; b < m_Tangents_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Tangents = new float[m_Tangents_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Tangents_Packed.m_NumItems / 2; v++) { m_Tangents[v * 3] = (float)((double)m_Tangents_Unpacked[v * 2] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; m_Tangents[v * 3 + 1] = (float)((double)m_Tangents_Unpacked[v * 2 + 1] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; m_Tangents[v * 3 + 2] = (float)Math.Sqrt(1 - m_Tangents[v * 3] * m_Tangents[v * 3] - m_Tangents[v * 3 + 1] * m_Tangents[v * 3 + 1]); if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; } } } #endregion #region m_FloatColors if (version[0] >= 5) { PackedBitVector m_FloatColors = new PackedBitVector(); m_FloatColors.m_NumItems = a_Stream.ReadInt32(); m_FloatColors.m_Range = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_FloatColors.m_Data, 0, m_FloatColors.m_Data.Length); a_Stream.AlignStream(4); m_FloatColors.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_FloatColors.m_NumItems > 0 && (bool)Properties.Settings.Default["exportColors"]) { uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); int bitmax = 0; for (int b = 0; b < m_FloatColors.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_FloatColors.m_NumItems]; for (int v = 0; v < m_FloatColors.m_NumItems; v++) { m_Colors[v] = (float)m_FloatColors_Unpacked[v] / bitmax * m_FloatColors.m_Range + m_FloatColors.m_Start; } } } #endregion #region m_Skin PackedBitVector m_BoneIndices = new PackedBitVector(); m_BoneIndices.m_NumItems = a_Stream.ReadInt32(); m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.AlignStream(4); m_BoneIndices.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment //how the hell does this work?? if (m_BoneIndices.m_NumItems > 0 && m_BoneIndices.m_NumItems == m_Weights.m_NumItems && (bool)Properties.Settings.Default["exportDeformers"]) { uint[] m_Weights_Unpacked = UnpackBitVector(m_Weights); int bitmax = 0; for (int b = 0; b < m_Weights.m_BitSize; b++) { bitmax |= (1 << b); } uint[] m_BoneIndices_Unpacked = UnpackBitVector(m_BoneIndices); m_Skin = new List<BoneInfluence>[m_BoneIndices.m_NumItems / 4]; for (int s = 0; s < m_Skin.Length; s++) { m_Skin[s] = new List<BoneInfluence>(); for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = (float)((double)m_Weights_Unpacked[s * 4 + i] / bitmax), boneIndex = (int)m_BoneIndices_Unpacked[s * 4 + i] }); } } } #endregion PackedBitVector m_Triangles = new PackedBitVector(); m_Triangles.m_NumItems = a_Stream.ReadInt32(); m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.AlignStream(4); m_Triangles.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Triangles.m_NumItems > 0) { m_IndexBuffer = UnpackBitVector(m_Triangles); } } #endregion #region Colors & Collision triangles for 3.4.2 and earlier if (version[0] <= 2 || (version[0] == 3 && version[1] <= 4)) // { a_Stream.Position += 24; //Axis-Aligned Bounding Box int m_Colors_size = a_Stream.ReadInt32(); m_Colors = new float[m_Colors_size * 4]; for (int v = 0; v < m_Colors_size * 4; v++) { m_Colors[v] = (float)(a_Stream.ReadByte()) / 0xFF; } int m_CollisionTriangles_size = a_Stream.ReadInt32(); a_Stream.Position += m_CollisionTriangles_size * 4; //UInt32 indices int m_CollisionVertexCount = a_Stream.ReadInt32(); } #endregion #region Compressed colors & Local AABB for 3.5.0 to 4.x.x else //vertex colors are either in streams or packed bits { if (version[0] < 5) { PackedBitVector m_Colors_Packed = new PackedBitVector(); m_Colors_Packed.m_NumItems = a_Stream.ReadInt32(); m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Colors_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Colors_Packed.m_NumItems > 0) { if (m_Colors_Packed.m_BitSize == 32) { //4 x 8bit color channels m_Colors = new float[m_Colors_Packed.m_Data.Length]; for (int v = 0; v < m_Colors_Packed.m_Data.Length; v++) { m_Colors[v] = (float)m_Colors_Packed.m_Data[v] / 0xFF; } } else //not tested { uint[] m_Colors_Unpacked = UnpackBitVector(m_Colors_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Colors_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_Colors_Packed.m_NumItems]; for (int v = 0; v < m_Colors_Packed.m_NumItems; v++) { m_Colors[v] = (float)m_Colors_Unpacked[v] / bitmax; } } } } else { uint m_UVInfo = a_Stream.ReadUInt32(); } a_Stream.Position += 24; //Axis-Aligned Bounding Box } #endregion int m_MeshUsageFlags = a_Stream.ReadInt32(); if (version[0] >= 5) { //int m_BakedConvexCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; //int m_BakedTriangleCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; } #region Build face indices for (int s = 0; s < m_SubMeshes_size; s++) { uint firstIndex = m_SubMeshes[s].firstByte / 2; if (!m_Use16BitIndices) { firstIndex /= 2; } if (m_SubMeshes[s].topology == 0) { for (int i = 0; i < m_SubMeshes[s].indexCount / 3; i++) { m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); m_materialIDs.Add(s); } } else { for (int i = 0; i < m_SubMeshes[s].indexCount - 2; i++) { uint fa = m_IndexBuffer[firstIndex + i]; uint fb = m_IndexBuffer[firstIndex + i + 1]; uint fc = m_IndexBuffer[firstIndex + i + 2]; if ((fa!=fb) && (fa!=fc) && (fc!=fb)) { m_Indices.Add(fa); if ((i % 2) == 0) { m_Indices.Add(fb); m_Indices.Add(fc); } else { m_Indices.Add(fc); m_Indices.Add(fb); } m_materialIDs.Add(s); } } } } #endregion }
public Mesh(AssetPreloadData MeshPD) { //Stream = new EndianStream(File.OpenRead(sourceFile.filePath), sourceFile.endianType); //Stream.endian = sourceFile.endianType; var version = MeshPD.sourceFile.version; a_Stream = MeshPD.sourceFile.a_Stream; a_Stream.Position = MeshPD.Offset; bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices uint m_MeshCompression = 0; if (MeshPD.sourceFile.platform == -2) { uint m_ObjectHideFlags = a_Stream.ReadUInt32(); PPtr m_PrefabParentObject = MeshPD.sourceFile.ReadPPtr(); PPtr m_PrefabInternal = MeshPD.sourceFile.ReadPPtr(); } m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_Use16BitIndices = a_Stream.ReadBoolean(); a_Stream.Position += 3; } #region Index Buffer for 2.5.1 and earlier if (version[0] == 2 && version[1] <= 5) { int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } } } #endregion int m_SubMeshes_size = a_Stream.ReadInt32(); for (int s = 0; s < m_SubMeshes_size; s++) { m_SubMeshes.Add(new SubMesh()); m_SubMeshes[s].firstByte = a_Stream.ReadUInt32(); m_SubMeshes[s].indexCount = a_Stream.ReadUInt32(); //what is this in case of triangle strips? m_SubMeshes[s].topology = a_Stream.ReadInt32(); //isTriStrip if (version[0] < 4) { m_SubMeshes[s].triangleCount = a_Stream.ReadUInt32(); } if (version[0] >= 3) { m_SubMeshes[s].firstVertex = a_Stream.ReadUInt32(); m_SubMeshes[s].vertexCount = a_Stream.ReadUInt32(); a_Stream.Position += 24; //Axis-Aligned Bounding Box } } #region m_Shapes for 4.1.0 and later, excluding 4.1.0 alpha if (version [0] >= 5 || (version[0] == 4 && (version[1] > 1 || (version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a")))) { if (version[0] == 4 && version[1] <= 2) //4.1.0f4 - 4.2.2f1 { int m_Shapes_size = a_Stream.ReadInt32(); if (m_Shapes_size > 0) { bool stop = true; } for (int s = 0; s < m_Shapes_size; s++) //untested { string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents } int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } else //4.3.0 and later { int m_ShapeVertices_size = a_Stream.ReadInt32(); a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index int shapes_size = a_Stream.ReadInt32(); a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents int channels_size = a_Stream.ReadInt32(); for (int c = 0; c < channels_size; c++) { string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount } int fullWeights_size = a_Stream.ReadInt32(); a_Stream.Position += fullWeights_size * 4; //floats int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 int m_BoneNameHashes_size = a_Stream.ReadInt32(); a_Stream.Position += m_BoneNameHashes_size * 4; //uints uint m_RootBoneNameHash = a_Stream.ReadUInt32(); } } #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { m_MeshCompression = a_Stream.ReadByte(); if (version[0] >= 4) { if (version[0] < 5) { uint m_StreamCompression = a_Stream.ReadByte(); } bool m_IsReadable = a_Stream.ReadBoolean(); bool m_KeepVertices = a_Stream.ReadBoolean(); bool m_KeepIndices = a_Stream.ReadBoolean(); } a_Stream.AlignStream(4); int m_IndexBuffer_size = a_Stream.ReadInt32(); if (m_Use16BitIndices) { m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } a_Stream.AlignStream(4); } else { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } //align?? } } #endregion #region Vertex Buffer for 3.4.2 and earlier if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) { m_VertexCount = a_Stream.ReadUInt32(); m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } int m_Skin_size = a_Stream.ReadInt32(); a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 int m_UV1_size = a_Stream.ReadInt32(); m_UV1 = new float[m_UV1_size * 2]; for (int v = 0; v < m_UV1_size * 2; v++) { m_UV1[v] = a_Stream.ReadSingle(); } int m_UV2_size = a_Stream.ReadInt32(); m_UV2 = new float[m_UV2_size * 2]; for (int v = 0; v < m_UV2_size * 2; v++) { m_UV2[v] = a_Stream.ReadSingle(); } if (version[0] == 2 && version[1] <= 5) { int m_TangentSpace_size = a_Stream.ReadInt32(); m_Normals = new float[m_TangentSpace_size * 3]; for (int v = 0; v < m_TangentSpace_size; v++) { m_Normals[v * 3] = a_Stream.ReadSingle(); m_Normals[v * 3 + 1] = a_Stream.ReadSingle(); m_Normals[v * 3 + 2] = a_Stream.ReadSingle(); a_Stream.Position += 16; //Vector3f tangent & float handedness } } else //2.6.0 and later { int m_Tangents_size = a_Stream.ReadInt32(); a_Stream.Position += m_Tangents_size * 16; //Vector4f int m_Normals_size = a_Stream.ReadInt32(); m_Normals = new float[m_Normals_size * 3]; for (int v = 0; v < m_Normals_size * 3; v++) { m_Normals[v] = a_Stream.ReadSingle(); } } } #endregion #region Vertex Buffer for 3.5.0 and later else { #region read vertex stream int m_Skin_size = a_Stream.ReadInt32(); a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices if (version[0] <= 3 || (version[0] == 4 && version[1] <= 2)) { int m_BindPose_size = a_Stream.ReadInt32(); a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 } int m_CurrentChannels = a_Stream.ReadInt32();//defined as uint in Unity m_VertexCount = a_Stream.ReadUInt32(); #region 3.5.0 - 3.5.7 if (version[0] < 4) { if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 { a_Stream.Position += 12; } else { m_Streams = new StreamInfo[4]; for (int s = 0; s < 4; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadInt32(); m_Streams[s].align = a_Stream.ReadUInt32(); } } } #endregion #region 4.0.0 and later else { int singleStreamStride = 0;//used tor unity 5 m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; for (int c = 0; c < m_Channels.Length; c++) { m_Channels[c] = new ChannelInfo(); m_Channels[c].stream = a_Stream.ReadByte(); m_Channels[c].offset = a_Stream.ReadByte(); m_Channels[c].format = a_Stream.ReadByte(); m_Channels[c].dimension = a_Stream.ReadByte(); //calculate stride for Unity 5 singleStreamStride += m_Channels[c].dimension * (m_Channels[c].format % 2 == 0 ? 4 : 2);//fingers crossed! } if (version[0] < 5) { m_Streams = new StreamInfo[a_Stream.ReadInt32()]; for (int s = 0; s < m_Streams.Length; s++) { m_Streams[s] = new StreamInfo(); m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); m_Streams[s].offset = a_Stream.ReadInt32(); m_Streams[s].stride = a_Stream.ReadByte(); m_Streams[s].dividerOp = a_Stream.ReadByte(); m_Streams[s].frequency = a_Stream.ReadUInt16(); } } else //it's just easier to create my own stream here { m_Streams = new StreamInfo[1]; m_Streams[0] = new StreamInfo(); m_Streams[0].channelMask = new BitArray(new int[1] { m_CurrentChannels }); m_Streams[0].offset = 0; m_Streams[0].stride = singleStreamStride; } } #endregion //actual Vertex Buffer byte[] m_DataSize = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_DataSize, 0, m_DataSize.Length); #endregion #region compute FvF byte valueBufferSize = 0; byte[] valueBuffer; float[] dstArray; if (m_Channels != null) { //it is better to loop channels instead of streams //because channels are likely to be sorted by vertex property #region 4.0.0 and later foreach (var m_Channel in m_Channels) { if (m_Channel.dimension > 0) { var m_Stream = m_Streams[m_Channel.stream]; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { 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;//these are actually groups of 4 components break; } valueBuffer = new byte[valueBufferSize]; dstArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); } } switch (b) { case 0://1 m_Vertices = dstArray; break; case 1://2 m_Normals = dstArray; break; case 2://4 m_Colors = dstArray; break; case 3://8 m_UV1 = dstArray; break; case 4://16 m_UV2 = dstArray; break; case 5://32 m_Tangents = dstArray; break; } m_Stream.channelMask.Set(b, false); //is this needed? valueBuffer = null; dstArray = null; break; //go to next channel } } } } } #endregion #region 3.5.0 - 3.5.7 else if (m_Streams != null) { foreach (var m_Stream in m_Streams) { //a stream may have multiple vertex components but without channels there are no offsets, so I assume all vertex properties are in order //Unity 3.5.x only uses floats, and that's probably why channels were introduced in Unity 4 ChannelInfo m_Channel = new ChannelInfo();//create my own channel so I can use the same methods m_Channel.offset = 0; for (int b = 0; b < 6; b++) { if (m_Stream.channelMask.Get(b)) { switch (b) { case 0: case 1: valueBufferSize = 4; m_Channel.dimension = 3; break; case 2: valueBufferSize = 1; m_Channel.dimension = 4; break; case 3: case 4: valueBufferSize = 4; m_Channel.dimension = 2; break; case 5: valueBufferSize = 4; m_Channel.dimension = 4; break; } valueBuffer = new byte[valueBufferSize]; dstArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { for (int d = 0; d < m_Channel.dimension; d++) { int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); } } switch (b) { case 0: m_Vertices = dstArray; break; case 1: m_Normals = dstArray; break; case 2: m_Colors = dstArray; break; case 3: m_UV1 = dstArray; break; case 4: m_UV2 = dstArray; break; case 5: m_Tangents = dstArray; break; } m_Channel.offset += (byte)(m_Channel.dimension * valueBufferSize); //strides larger than 255 are unlikely m_Stream.channelMask.Set(b, false); //is this needed? valueBuffer = null; dstArray = null; } } } } #endregion #endregion } #endregion #region Compressed Mesh data for 2.6.0 and later - 160 bytes if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) { //remember there can be combinations of packed and regular vertex properties PackedBitVector m_Vertices_Packed = new PackedBitVector(); m_Vertices_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Vertices_Packed.m_Data, 0, m_Vertices_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Vertices_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Vertices_Packed.m_NumItems > 0) { m_VertexCount = m_Vertices_Packed.m_NumItems / 3; uint[] m_Vertices_Unpacked = UnpackBitVector(m_Vertices_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Vertices = new float[m_Vertices_Packed.m_NumItems]; for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) { m_Vertices[v] = (float)m_Vertices_Unpacked[v] / bitmax * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; } } PackedBitVector m_UV_Packed = new PackedBitVector(); //contains both channels m_UV_Packed.m_NumItems = a_Stream.ReadUInt32(); m_UV_Packed.m_Range = a_Stream.ReadSingle(); m_UV_Packed.m_Start = a_Stream.ReadSingle(); m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_UV_Packed.m_Data, 0, m_UV_Packed.m_Data.Length); m_UV_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_UV_Packed.m_NumItems > 0) { uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); int bitmax = 0; for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_UV1 = new float[m_VertexCount * 2]; for (int v = 0; v < m_VertexCount * 2; v++) { m_UV1[v] = (float)m_UV_Unpacked[v] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } if (m_UV_Packed.m_NumItems == m_VertexCount * 4) { m_UV2 = new float[m_VertexCount * 2]; for (uint v = 0; v < m_VertexCount * 2; v++) { m_UV2[v] = (float)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; } } } if (version[0] < 5) { PackedBitVector m_BindPoses_Packed = new PackedBitVector(); m_BindPoses_Packed.m_NumItems = a_Stream.ReadUInt32(); m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BindPoses_Packed.m_Data, 0, m_BindPoses_Packed.m_Data.Length); a_Stream.AlignStream(4); m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment } PackedBitVector m_Normals_Packed = new PackedBitVector(); m_Normals_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Normals_Packed.m_Range = a_Stream.ReadSingle(); m_Normals_Packed.m_Start = a_Stream.ReadSingle(); m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Normals_Packed.m_Data, 0, m_Normals_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Normals_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Tangents_Packed = new PackedBitVector(); m_Tangents_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Tangents_Packed.m_Data, 0, m_Tangents_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Weights_Packed = new PackedBitVector(); m_Weights_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Weights_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Weights_Packed.m_Data, 0, m_Weights_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Weights_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_NormalSigns_packed = new PackedBitVector(); m_NormalSigns_packed.m_NumItems = a_Stream.ReadUInt32(); m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); a_Stream.AlignStream(4); m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Normals_Packed.m_NumItems > 0) { uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); int bitmax = 0; for (int b = 0; b < m_Normals_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Normals = new float[m_Normals_Packed.m_NumItems / 2 * 3]; for (int v = 0; v < m_Normals_Packed.m_NumItems / 2; v++) { m_Normals[v * 3] = (float)((double)m_Normals_Unpacked[v * 2] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 1] = (float)((double)m_Normals_Unpacked[v * 2 + 1] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; m_Normals[v * 3 + 2] = (float)Math.Sqrt(1 - m_Normals[v * 3] * m_Normals[v * 3] - m_Normals[v * 3 + 1] * m_Normals[v * 3 + 1]); if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } } } PackedBitVector m_TangentSigns = new PackedBitVector(); m_TangentSigns.m_NumItems = a_Stream.ReadUInt32(); m_TangentSigns.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_TangentSigns.m_Data, 0, m_TangentSigns.m_Data.Length); a_Stream.AlignStream(4); m_TangentSigns.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (version[0] >= 5) { PackedBitVector m_FloatColors = new PackedBitVector(); m_FloatColors.m_NumItems = a_Stream.ReadUInt32(); m_FloatColors.m_Range = a_Stream.ReadSingle(); m_FloatColors.m_Start = a_Stream.ReadSingle(); m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_FloatColors.m_Data, 0, m_FloatColors.m_Data.Length); a_Stream.AlignStream(4); m_FloatColors.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_FloatColors.m_NumItems > 0) { uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); int bitmax = 0; for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_FloatColors.m_NumItems]; for (int v = 0; v < m_FloatColors.m_NumItems; v++) { m_Colors[v] = (float)m_FloatColors_Unpacked[v] / bitmax * m_FloatColors.m_Range + m_FloatColors.m_Start; } } } PackedBitVector m_BoneIndices = new PackedBitVector(); m_BoneIndices.m_NumItems = a_Stream.ReadUInt32(); m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); a_Stream.AlignStream(4); m_BoneIndices.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment PackedBitVector m_Triangles = new PackedBitVector(); m_Triangles.m_NumItems = a_Stream.ReadUInt32(); m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); a_Stream.AlignStream(4); m_Triangles.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Triangles.m_NumItems > 0) { m_IndexBuffer = UnpackBitVector(m_Triangles); } } #endregion #region Colors & Collision triangles for 3.4.2 and earlier if (version[0] <= 2 || (version[0] == 3 && version[1] <= 4)) // { a_Stream.Position += 24; //Axis-Aligned Bounding Box int m_Colors_size = a_Stream.ReadInt32(); m_Colors = new float[m_Colors_size * 4]; for (int v = 0; v < m_Colors_size * 4; v++) { m_Colors[v] = (float)(a_Stream.ReadByte()) / 0xFF; } int m_CollisionTriangles_size = a_Stream.ReadInt32(); a_Stream.Position += m_CollisionTriangles_size * 4; //UInt32 indices int m_CollisionVertexCount = a_Stream.ReadInt32(); } #endregion #region Compressed colors & Local AABB for 3.5.0 to 4.x.x else //vertex colors are either in streams or packed bits { if (version[0] < 5) { PackedBitVector m_Colors_Packed = new PackedBitVector(); m_Colors_Packed.m_NumItems = a_Stream.ReadUInt32(); m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); a_Stream.AlignStream(4); m_Colors_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment if (m_Colors_Packed.m_NumItems > 0) { if (m_Colors_Packed.m_BitSize == 32) { //4 x 8bit color channels m_Colors = new float[m_Colors_Packed.m_Data.Length]; for (int v = 0; v < m_Colors_Packed.m_Data.Length; v++) { m_Colors[v] = (float)m_Colors_Packed.m_Data[v] / 0xFF; } } else //not tested { uint[] m_Colors_Unpacked = UnpackBitVector(m_Colors_Packed); int bitmax = 0;//used to convert int value to float for (int b = 0; b < m_Colors_Packed.m_BitSize; b++) { bitmax |= (1 << b); } m_Colors = new float[m_Colors_Packed.m_NumItems]; for (int v = 0; v < m_Colors_Packed.m_NumItems; v++) { m_Colors[v] = (float)m_Colors_Unpacked[v] / bitmax; } } } } a_Stream.Position += 24; //Axis-Aligned Bounding Box } #endregion int m_MeshUsageFlags = a_Stream.ReadInt32(); if (version[0] >= 5) { //int m_BakedConvexCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; //int m_BakedTriangleCollisionMesh = a_Stream.ReadInt32(); //a_Stream.Position += m_BakedConvexCollisionMesh; } #region Build face indices for (int s = 0; s < m_SubMeshes_size; s++) { uint firstIndex = m_SubMeshes[s].firstByte / 2; if (!m_Use16BitIndices) { firstIndex /= 2; } if (m_SubMeshes[s].topology == 0) { for (int i = 0; i < m_SubMeshes[s].indexCount / 3; i++) { m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); m_materialIDs.Add(s); } } else { for (int i = 0; i < m_SubMeshes[s].indexCount - 2; i++) { uint fa = m_IndexBuffer[firstIndex + i]; uint fb = m_IndexBuffer[firstIndex + i + 1]; uint fc = m_IndexBuffer[firstIndex + i + 2]; if ((fa!=fb) && (fa!=fc) && (fc!=fb)) { m_Indices.Add(fa); if ((i % 2) == 0) { m_Indices.Add(fb); m_Indices.Add(fc); } else { m_Indices.Add(fc); m_Indices.Add(fb); } m_materialIDs.Add(s); } } } } #endregion }
private static void Read(StringBuilder sb, List <ClassMember> members, EndianStream a_Stream) { for (int i = 0; i < members.Count; i++) { var member = members[i]; var level = member.Level; var varTypeStr = member.Type; var varNameStr = member.Name; object value = null; var align = (member.Flag & 0x4000) != 0; var append = true; if (varTypeStr == "SInt8")//sbyte { value = a_Stream.ReadSByte(); } else if (varTypeStr == "UInt8")//byte { value = a_Stream.ReadByte(); } else if (varTypeStr == "short" || varTypeStr == "SInt16")//Int16 { value = a_Stream.ReadInt16(); } else if (varTypeStr == "UInt16" || varTypeStr == "unsigned short")//UInt16 { value = a_Stream.ReadUInt16(); } else if (varTypeStr == "int" || varTypeStr == "SInt32")//Int32 { value = a_Stream.ReadInt32(); } else if (varTypeStr == "UInt32" || varTypeStr == "unsigned int")//UInt32 { value = a_Stream.ReadUInt32(); } else if (varTypeStr == "long long" || varTypeStr == "SInt64")//Int64 { value = a_Stream.ReadInt64(); } else if (varTypeStr == "UInt64" || varTypeStr == "unsigned long long")//UInt64 { value = a_Stream.ReadUInt64(); } else if (varTypeStr == "float")//float { value = a_Stream.ReadSingle(); } else if (varTypeStr == "double")//double { value = a_Stream.ReadDouble(); } else if (varTypeStr == "bool")//bool { value = a_Stream.ReadBoolean(); } else if (varTypeStr == "string")//string { append = false; var str = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str); i += 3; //skip } else if (varTypeStr == "Array") //Array { append = false; if ((members[i - 1].Flag & 0x4000) != 0) { align = true; } sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); var size = a_Stream.ReadInt32(); sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), "int", "size", size); var array = ReadArray(members, level, i); for (int j = 0; j < size; j++) { sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 1)), j); Read(sb, array, a_Stream); } i += array.Count + 1;//skip } else { append = false; align = false; sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); } if (append) { sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), varTypeStr, varNameStr, value); } if (align) { a_Stream.AlignStream(4); } } }