internal void Read(EndianBinaryReader reader, ObjectSection section = null) { reader.SeekCurrent(4); // Unused flags BoundingSphere = reader.ReadBoundingSphere(); int subMeshCount = reader.ReadInt32(); long subMeshesOffset = reader.ReadOffset(); var vertexFormat = ( VertexFormatAttributes )reader.ReadUInt32(); int vertexSize = reader.ReadInt32(); int vertexCount = reader.ReadInt32(); var attributeOffsets = reader.ReadOffsets(20); Flags = ( MeshFlags )reader.ReadInt32(); uint attributeFlags = reader.ReadUInt32(); reader.SkipNulls(6 * sizeof(uint)); Name = reader.ReadString(StringBinaryFormat.FixedLength, 64); reader.ReadAtOffset(subMeshesOffset, () => { SubMeshes.Capacity = subMeshCount; for (int i = 0; i < subMeshCount; i++) { var subMesh = new SubMesh(); subMesh.Read(reader, section); SubMeshes.Add(subMesh); } }); // Modern Format if ((vertexFormat & VertexFormatAttributes.UsesModernStorage) != 0) { ReadVertexAttributesModern(); } else { ReadVertexAttributesClassic(); } void ReadVertexAttributesClassic() { Vector4[] boneWeights = null; Vector4[] boneIndices = null; for (int i = 0; i < attributeOffsets.Length; i++) { var attribute = ( VertexFormatAttributes )(1 << i); reader.ReadAtOffsetIf((vertexFormat & attribute) != 0, attributeOffsets[i], () => { switch (attribute) { case VertexFormatAttributes.Position: Positions = reader.ReadVector3s(vertexCount); break; case VertexFormatAttributes.Normal: Normals = reader.ReadVector3s(vertexCount); break; case VertexFormatAttributes.Tangent: Tangents = reader.ReadVector4s(vertexCount); break; case VertexFormatAttributes.TexCoord0: TexCoords0 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord1: TexCoords1 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord2: TexCoords2 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord3: TexCoords3 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.Color0: Colors0 = reader.ReadColors(vertexCount); break; case VertexFormatAttributes.Color1: Colors1 = reader.ReadColors(vertexCount); break; case VertexFormatAttributes.BoneWeight: boneWeights = reader.ReadVector4s(vertexCount); break; case VertexFormatAttributes.BoneIndex: boneIndices = reader.ReadVector4s(vertexCount); break; default: Console.WriteLine("Unhandled vertex format element: {0}", attribute); break; } }); } if (boneWeights == null || boneIndices == null) { return; } BoneWeights = new BoneWeight[vertexCount]; for (int i = 0; i < vertexCount; i++) { var weight4 = boneWeights[i]; var index4 = Vector4.Divide(boneIndices[i], 3); var boneWeight = new BoneWeight { Weight1 = weight4.X, Weight2 = weight4.Y, Weight3 = weight4.Z, Weight4 = weight4.W, Index1 = ( int )index4.X, Index2 = ( int )index4.Y, Index3 = ( int )index4.Z, Index4 = ( int )index4.W }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } } void ReadVertexAttributesModern() { Positions = new Vector3[vertexCount]; Normals = new Vector3[vertexCount]; Tangents = new Vector4[vertexCount]; TexCoords0 = new Vector2[vertexCount]; TexCoords1 = new Vector2[vertexCount]; if (attributeFlags == 10) { TexCoords2 = new Vector2[vertexCount]; TexCoords3 = new Vector2[vertexCount]; } else if (attributeFlags == 6) { TexCoords2 = new Vector2[vertexCount]; } Colors0 = new Color[vertexCount]; if (attributeFlags == 4) { BoneWeights = new BoneWeight[vertexCount]; } bool hasTangents = false; EndianBinaryReader vertexReader; long baseOffset; if (section != null) { vertexReader = section.VertexData.Reader; baseOffset = section.VertexData.DataOffset; } else { vertexReader = reader; baseOffset = reader.BaseOffset; } long current = reader.Position; for (int i = 0; i < vertexCount; i++) { vertexReader.SeekBegin(baseOffset + attributeOffsets[13] + vertexSize * i); Positions[i] = vertexReader.ReadVector3(); Normals[i] = vertexReader.ReadVector3(VectorBinaryFormat.Int16); vertexReader.SeekCurrent(2); Tangents[i] = vertexReader.ReadVector4(VectorBinaryFormat.Int16); TexCoords0[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); TexCoords1[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); if (attributeFlags == 10) { TexCoords2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); TexCoords3[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); } else if (attributeFlags == 6) { TexCoords2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); } Colors0[i] = vertexReader.ReadColor(VectorBinaryFormat.Half); if (attributeFlags == 4) { var boneWeight = new BoneWeight { Weight1 = vertexReader.ReadUInt16() / 32767f, Weight2 = vertexReader.ReadUInt16() / 32767f, Weight3 = vertexReader.ReadUInt16() / 32767f, Weight4 = vertexReader.ReadUInt16() / 32767f, Index1 = vertexReader.ReadByte() / 3, Index2 = vertexReader.ReadByte() / 3, Index3 = vertexReader.ReadByte() / 3, Index4 = vertexReader.ReadByte() / 3 }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } // Normalize normal because precision Normals[i] = Vector3.Normalize(Normals[i]); // Checks to get rid of useless data after reading if (Tangents[i] != Vector4.Zero) { hasTangents = true; } } if (!hasTangents) { Tangents = null; } reader.SeekBegin(current); } if (Tangents == null) { return; } for (int i = 0; i < Tangents.Length; i++) { int direction = Math.Sign(Tangents[i].W); var tangent = Vector3.Normalize(new Vector3(Tangents[i].X, Tangents[i].Y, Tangents[i].Z)); Tangents[i] = new Vector4(tangent, direction); } }
internal void Read(EndianBinaryReader reader, ObjectSection section = null) { reader.SeekCurrent(4); BoundingSphere = reader.ReadBoundingSphere(); int subMeshCount = reader.ReadInt32(); long subMeshesOffset = reader.ReadOffset(); var attributes = ( VertexFormatAttribute )reader.ReadUInt32(); int stride = reader.ReadInt32(); int vertexCount = reader.ReadInt32(); var elemItems = reader.ReadUInt32s(section?.Format == BinaryFormat.X ? 49 : 28); Name = reader.ReadString(StringBinaryFormat.FixedLength, 64); SubMeshes.Capacity = subMeshCount; for (int i = 0; i < subMeshCount; i++) { reader.ReadAtOffset(subMeshesOffset + i * SubMesh.GetByteSize(section?.Format ?? BinaryFormat.DT), () => { var subMesh = new SubMesh(); subMesh.Read(reader, section); SubMeshes.Add(subMesh); }); } // Modern Format if (section != null) { ReadVertexAttributesModern(); } else { ReadVertexAttributesClassic(); } void ReadVertexAttributesClassic() { Vector4[] boneWeights = null; Vector4[] boneIndices = null; for (int i = 0; i < 28; i++) { var attribute = ( VertexFormatAttribute )(1 << i); reader.ReadAtOffsetIf((attributes & attribute) != 0, elemItems[i], () => { switch (attribute) { case VertexFormatAttribute.Vertex: Vertices = reader.ReadVector3s(vertexCount); break; case VertexFormatAttribute.Normal: Normals = reader.ReadVector3s(vertexCount); break; case VertexFormatAttribute.Tangent: Tangents = reader.ReadVector4s(vertexCount); break; case VertexFormatAttribute.UVChannel1: UVChannel1 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttribute.UVChannel2: UVChannel2 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttribute.Color: Colors = reader.ReadColors(vertexCount); break; case VertexFormatAttribute.BoneWeight: boneWeights = reader.ReadVector4s(vertexCount); break; case VertexFormatAttribute.BoneIndex: boneIndices = reader.ReadVector4s(vertexCount); break; default: Console.WriteLine("Unhandled vertex format element: {0}", attribute); break; } }); } if (boneWeights != null && boneIndices != null) { BoneWeights = new BoneWeight[vertexCount]; for (int i = 0; i < vertexCount; i++) { var weight4 = boneWeights[i]; var index4 = Vector4.Divide(boneIndices[i], 3); var boneWeight = new BoneWeight { Weight1 = weight4.X, Weight2 = weight4.Y, Weight3 = weight4.Z, Weight4 = weight4.W, Index1 = ( int )index4.X, Index2 = ( int )index4.Y, Index3 = ( int )index4.Z, Index4 = ( int )index4.W }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } } } void ReadVertexAttributesModern() { uint dataOffset = elemItems[section.Format == BinaryFormat.X ? 27 : 13]; uint attributeFlags = elemItems[section.Format == BinaryFormat.X ? 42 : 21]; if (attributeFlags == 2 || attributeFlags == 4) { Vertices = new Vector3[vertexCount]; Normals = new Vector3[vertexCount]; Tangents = new Vector4[vertexCount]; UVChannel1 = new Vector2[vertexCount]; UVChannel2 = new Vector2[vertexCount]; Colors = new Color[vertexCount]; if (attributeFlags == 4) { BoneWeights = new BoneWeight[vertexCount]; } bool hasTangents = false; bool hasUVChannel2 = false; bool hasColors = false; var vertexReader = section.VertexData.Reader; for (int i = 0; i < vertexCount; i++) { vertexReader.SeekBegin(section.VertexData.DataOffset + dataOffset + stride * i); Vertices[i] = vertexReader.ReadVector3(); Normals[i] = vertexReader.ReadVector3(VectorBinaryFormat.Int16); vertexReader.SeekCurrent(2); Tangents[i] = vertexReader.ReadVector4(VectorBinaryFormat.Int16); UVChannel1[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); UVChannel2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); Colors[i] = vertexReader.ReadColor(VectorBinaryFormat.Half); if (attributeFlags == 4) { var boneWeight = new BoneWeight { Weight1 = vertexReader.ReadUInt16() / 32767f, Weight2 = vertexReader.ReadUInt16() / 32767f, Weight3 = vertexReader.ReadUInt16() / 32767f, Weight4 = vertexReader.ReadUInt16() / 32767f, Index1 = vertexReader.ReadByte() / 3, Index2 = vertexReader.ReadByte() / 3, Index3 = vertexReader.ReadByte() / 3, Index4 = vertexReader.ReadByte() / 3 }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } // Normalize normal because precision Normals[i] = Vector3.Normalize(Normals[i]); // Checks to get rid of useless data after reading if (Tangents[i] != Vector4.Zero) { hasTangents = true; } if (UVChannel1[i] != UVChannel2[i]) { hasUVChannel2 = true; } if (!Colors[i].Equals(Color.White)) { hasColors = true; } } if (!hasTangents) { Tangents = null; } if (!hasUVChannel2) { UVChannel2 = null; } if (!hasColors) { Colors = null; } } if (Tangents != null) { for (int i = 0; i < Tangents.Length; i++) { int direction = Math.Sign(Tangents[i].W); var tangent = Vector3.Normalize(new Vector3(Tangents[i].X, Tangents[i].Y, Tangents[i].Z)); Tangents[i] = new Vector4(tangent, direction); } } } }