private void ReadPmg(BinaryReader r) { var version = r.ReadByte(); if (version != PmgVersion) { throw new NotSupportedException($"pmg version {version} is not supported."); } var signature = ReadPmgSignature(r); if (signature != PmgSignature) { throw new InvalidDataException($"Not a pmg file? Expected '{PmgSignature}', got '{signature}'"); } var pieceCount = r.ReadUInt32(); var partCount = r.ReadUInt32(); var boneCount = r.ReadUInt32(); var weightWidth = r.ReadInt32(); var locatorCount = r.ReadUInt32(); var skeletonHash = r.ReadUInt64(); BoundingBoxCenter = r.ReadVector3(); BoundingBoxDiagonalSize = r.ReadSingle(); BoundingBox = new AxisAlignedBox(); BoundingBox.Deserialize(r); var skeletonOffset = r.ReadUInt32(); var partsOffset = r.ReadUInt32(); var locatorsOffset = r.ReadUInt32(); var piecesOffset = r.ReadUInt32(); var stringPoolOffset = r.ReadUInt32(); var stringPoolSize = r.ReadUInt32(); var vertexPoolOffset = r.ReadUInt32(); var vertexPoolSize = r.ReadUInt32(); var indexPoolOffset = r.ReadUInt32(); var indexPoolSize = r.ReadUInt32(); Skeleton = r.ReadObjectList<Bone>(boneCount); // jump ahead and read all locators & pieces first r.BaseStream.Position = locatorsOffset; var locators = r.ReadObjectList<Locator>(locatorCount); var pieces = r.ReadObjectList<Piece>(pieceCount); // then return to parts and assign the locators and pieces right away r.BaseStream.Position = partsOffset; for (int i = 0; i < partCount; i++) { var part = new Part(); part.Name = r.ReadToken(); var piecesCount = r.ReadUInt32(); var piecesIndex = r.ReadUInt32(); part.Pieces = pieces.GetRange((int)piecesIndex, (int)piecesCount); var locatorsCount = r.ReadUInt32(); var locatorsIndex = r.ReadUInt32(); part.Locators = locators.GetRange((int)locatorsIndex, (int)locatorsCount); Parts.Add(part); } // TODO: what is this? r.BaseStream.Position = stringPoolOffset; if (stringPoolSize > 0) { r.BaseStream.Position = stringPoolOffset; var stringsBytes = r.ReadBytes((int)stringPoolSize); strings = StringUtils.CStringBytesToList(stringsBytes); } }
/// <summary> /// ! BE ADVISED ! <br /> /// I usually prefer deserialization to be forward-only, /// but with this particular file structure, the reader /// has to jump back and forth a few times. /// </summary> /// <param name="r"></param> public void Deserialize(BinaryReader r) { var edges = r.ReadUInt32(); var verts = r.ReadUInt32(); var texCoordMask = r.ReadUInt32(); // what is this even used for? TextureCoordinateWidth = r.ReadInt32(); Material = r.ReadUInt32(); BoundingBoxCenter = r.ReadVector3(); BoundingBoxDiagonalSize = r.ReadSingle(); BoundingBox = new AxisAlignedBox(); BoundingBox.Deserialize(r); // TODO: Why does this even point to when the // model has no bones?? // used values are 36, 44 and 52? skeletonOffset_temp = r.ReadInt32(); var vertPositionOffset = r.ReadInt32(); var vertNormalOffset = r.ReadInt32(); var vertTexcoordOffset = r.ReadInt32(); var vertColorOffset = r.ReadInt32(); var vertColor2Offset = r.ReadInt32(); var vertTangentOffset = r.ReadInt32(); var vertBoneIndexOffset = r.ReadInt32(); var vertBoneWeightOffset = r.ReadInt32(); var indexOffset = r.ReadInt32(); UseTangents = (vertTangentOffset != Unused); UseSecondaryColor = (vertColor2Offset != Unused); UseTextureCoordinates = (vertTexcoordOffset != Unused); UseBoneIndexes = (vertBoneIndexOffset != Unused); UseBoneWeights = (vertBoneWeightOffset != Unused); var prevStreamPosition = r.BaseStream.Position; r.BaseStream.Position = vertPositionOffset; for (int i = 0; i < verts; i++) { var vertex = new Vertex(r.ReadVector3(), r.ReadVector3()); if (vertTangentOffset != Unused) { vertex.Tangent = r.ReadVector4(); } vertex.Color = r.ReadColor(); if (vertColor2Offset != Unused) { vertex.SecondaryColor = r.ReadColor(); } if (vertTexcoordOffset != Unused) { vertex.TextureCoordinates = r.ReadObjectList <Vector2>((uint)TextureCoordinateWidth); } if (vertBoneIndexOffset != Unused) { vertex.BoneIndexes = r.ReadBytes(4); } if (vertBoneWeightOffset != Unused) { vertex.BoneWeights = r.ReadBytes(4); } Vertices.Add(vertex); } r.BaseStream.Position = indexOffset; for (int i = 0; i < edges / 3; i++) { var t = new Triangle(); t.Deserialize(r); Triangles.Add(t); } r.BaseStream.Position = prevStreamPosition; }