Exemple #1
0
        /// <summary>
        /// Read a single grid index from MP.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public GridIndex(DhBinaryReader br)
        {
            // Read TotalTriangleGroupIndex.
            TotalTriangleGroupIndex = br.ReadS32();

            // Read FloorTriangleGroupIndex.
            FloorTriangleGroupIndex = br.ReadS32();
        }
Exemple #2
0
        /// <summary>
        /// Read a single material from BIN.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public BinMaterial(DhBinaryReader br)
        {
            // Read Index.
            Index = br.ReadS16();

            // Read Unknown 1. (Unused index?)
            Unknown1 = br.ReadS16();

            // Read U-Wrapping.
            WrapU = br.Read();

            // Read V-Wrapping.
            WrapV = br.Read();

            // Read Unknown 2. (Flags?)
            Unknown2 = br.ReadS16();

            // Define a array to hold the unknown 3 values.
            Unknown3 = new int[3];

            // Loop through the unknown 3 values.
            for (int i = 0; i < Unknown3.Length; i++)
            {
                // Write the current unknown value.
                Unknown3[i] = br.ReadS32();
            }
        }
Exemple #3
0
        /// <summary>
        /// Read a single entry from BAS.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public BasEntry(DhBinaryReader br)
        {
            // Read Id.
            Id = br.ReadU32();

            // Read Gain.
            Gain = br.ReadF32();

            // Read Delay / Length.
            Delay = br.ReadF32();

            // Read Pitch.
            Pitch = br.ReadF32();

            // Read Unknown 1.
            Unknown1 = br.ReadS32();

            // Read Balance.
            Balance = br.Read();

            // Read Unknown 2.
            Unknown2 = br.Read();

            // Read Unknown 3.
            Unknown3 = br.Read();

            // Read Unknown 4.
            Unknown4 = br.Read();

            // Read Padding.
            Padding = br.ReadU32s(2);
        }
Exemple #4
0
        /// <summary>
        /// Read a single entry from JMP.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        /// <param name="fields">List of fields in JMP.</param>
        public JEntry(DhBinaryReader br, List <JField> fields)
        {
            long currentPosition = br.Position();

            Values = new Dictionary <string, object>();
            for (int i = 0; i < fields.Count; i++)
            {
                br.Sail(fields[i].Offset);

                object value;
                switch (fields[i].Type)
                {
                case JFieldType.INTEGER:
                    value = ((br.ReadS32() & fields[i].Bitmask) >> fields[i].Shift);
                    break;

                case JFieldType.STRING:
                    value = br.ReadFixedStr(32);
                    break;

                case JFieldType.FLOAT:
                    value = br.ReadF32();
                    break;

                default:
                    throw new InvalidDataException($"{fields[i].Type} is not a valid jmp entry type!");
                }

                Values.Add(fields[i].Name, value);

                br.Goto(currentPosition);
            }
        }
Exemple #5
0
        /// <summary>
        /// Read a PrmEntry from PRM.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public PrmEntry(DhBinaryReader br)
        {
            // Read Hash.
            Hash = br.ReadU16();

            // Read NameLength.
            NameLength = br.ReadU16();

            // Read Name.
            Name = br.ReadStr(NameLength);

            // Read ValueLength.
            ValueLength = br.ReadU32();

            // Resolve Type from Hash.
            Type = PRMUtils.HashToType(Hash);

            // Check Type.
            switch (Type)
            {
            case PrmType.BYTE:

                // Read Value as a byte.
                Value = br.Read();
                break;

            case PrmType.SHORT:

                // Read Value as a short.
                Value = br.ReadS16();
                break;

            case PrmType.INT:

                // Read Value as a int.
                Value = br.ReadS32();
                break;

            case PrmType.FLOAT:

                // Read Value as a float.
                Value = br.ReadF32();
                break;

            case PrmType.RGBA:

                // Read Value as a Clr4.
                Value = br.ReadClr4();
                break;

            case PrmType.VECTOR3:

                // Read Value as a Vector3.
                Value = br.ReadVec3();
                break;

            default:
                throw new NotImplementedException("PRM parameter entry type is unknown!");
            }
        }
Exemple #6
0
        /// <summary>
        /// Read a SpritePoint from GEB.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public SpritePoint(DhBinaryReader br)
        {
            // Read SpritePoint's Position.
            Position = new Vector2(br.ReadF32(), br.ReadF32());

            // Read SpritePoint's Unknown 1.
            Unknown1 = br.ReadS32();
        }
Exemple #7
0
        public MDLHeader(DhBinaryReader br)
        {
            // magic
            Magic = br.ReadU32();

            // counts
            FaceCount              = br.ReadU16();
            Padding                = br.ReadS16();
            NodeCount              = br.ReadU16();
            PacketCount            = br.ReadU16();
            WeightCount            = br.ReadU16();
            JointCount             = br.ReadU16();
            PositionCount          = br.ReadU16();
            NormalCount            = br.ReadU16();
            ColorCount             = br.ReadU16();
            TextureCoordinateCount = br.ReadU16();
            Padding2               = br.ReadS64();
            TextureCount           = br.ReadU16();
            Padding3               = br.ReadS16();
            SamplerCount           = br.ReadU16();
            DrawElementCount       = br.ReadU16();
            MaterialCount          = br.ReadU16();
            ShapeCount             = br.ReadU16();
            Padding4               = br.ReadS32();

            // offsets
            NodeOffset              = br.ReadU32();
            PacketOffset            = br.ReadU32();
            MatricesOffset          = br.ReadU32();
            WeightOffset            = br.ReadU32();
            JointOffset             = br.ReadU32();
            WeightCountTableOffset  = br.ReadU32();
            PositionOffset          = br.ReadU32();
            NormalOffset            = br.ReadU32();
            ColorOffset             = br.ReadU32();
            TextureCoordinateOffset = br.ReadU32();
            Padding5 = br.ReadS64();
            TextureLocationOffset = br.ReadU32();
            Padding6          = br.ReadS32();
            MaterialOffset    = br.ReadU32();
            SamplerOffset     = br.ReadU32();
            ShapeOffset       = br.ReadU32();
            DrawElementOffset = br.ReadU32();
            Padding7          = br.ReadS64();
        }
Exemple #8
0
 public MDLNode(DhBinaryReader br, List <MDLDrawElement> drawElements)
 {
     MatrixIndex           = br.ReadU16();
     ChildIndex            = br.ReadU16();
     SiblingIndex          = br.ReadU16();
     Padding1              = br.ReadS16();
     DrawElementCount      = br.ReadU16();
     DrawElementBeginIndex = br.ReadU16();
     Padding2              = br.ReadS32();
     DrawElements          = drawElements.GetRange(DrawElementBeginIndex, DrawElementCount);
 }
Exemple #9
0
        /// <summary>
        /// Reads ANM from a data stream.
        /// </summary>
        /// <param name="stream">The stream containing the ANM data.</param>
        public ANM(Stream stream)
        {
            // Define a binary reader to read with.
            DhBinaryReader br = new DhBinaryReader(stream, DhEndian.Big);

            // Reader ANM's Header.
            Version        = br.ReadU8();
            Loop           = br.ReadBool8();
            Unknown1       = br.ReadS16();
            KeyFrameCount  = br.ReadU32();
            KeyFrameOffset = br.ReadU32();
            Unknown2       = br.ReadS32();
            Unknown3       = br.ReadS32();
            Unknown4       = br.ReadS32();

            /*
             *  Keyframes - Interpolation type list:
             *  https://ia800802.us.archive.org/9/items/GCN_SDK_Documentation/Game%20Engine%20Programming.pdf
             */
        }
Exemple #10
0
        /// <summary>
        /// Read a GSprite from GEB.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public GSprite(DhBinaryReader br)
        {
            // Read GSprite's Unknown 1.
            Unknown1 = br.ReadS16();

            // Read GSprite's Unknown 2.
            Unknown2 = br.ReadS16();

            // Read GSprite's RGBA.
            RGBA = br.ReadS32();

            // Define a new list to hold the GSprite's points.
            Points = new List <SpritePoint>();

            // Loop through GSprite's points.
            for (int i = 0; i < 4; i++)
            {
                // Read point and add it to the spritepoint list.
                Points.Add(new SpritePoint(br));
            }

            // Define a array to hold the unknown values.
            Unknown3 = new int[10];

            // Loop through the unknown values.
            for (int i = 0; i < Unknown3.Length; i++)
            {
                // Read the current unknown value.
                Unknown3[i] = br.ReadS32();
            }

            // Read GSprite's Unknown 4.
            Unknown4 = br.ReadF32();

            // Read GSprite's Unknown 5.
            Unknown5 = br.ReadF32();

            // Read GSprite's Unknown 6.
            Unknown6 = br.ReadS32();
        }
Exemple #11
0
        /// <summary>
        /// Read a single entry in TXP.
        /// </summary>
        /// <param name="br">The binaryreader to read with.</param>
        /// <param name="keyFrameCount">The amount of keyframes in each entry.</param>
        public TxpEntry(DhBinaryReader br, ushort keyFrameCount)
        {
            // Read Unknown 1.
            Unknown1 = br.ReadS16();

            //Read Material Index.
            MaterialIndex = br.ReadU16();

            // Read Unknown 2.
            Unknown2 = br.ReadS32();

            // Read Indices Offset.
            IndicesOffset = br.ReadU32();

            // Read Indices.
            Indices = br.ReadU16sAt(IndicesOffset, keyFrameCount).ToList();
        }
Exemple #12
0
        /// <summary>
        /// Read a single entry from JMP.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        /// <param name="fields">List of fields in JMP.</param>
        public JEntry(DhBinaryReader br, List <JField> fields)
        {
            // Save the current position.
            long currentPosition = br.Position();

            // Define a new object array to hold entry's values.
            Values = new object[fields.Count];

            // Loop through each field in the JMP.
            for (int i = 0; i < fields.Count; i++)
            {
                // Seek from the current position to value's offset in the entry.
                br.Sail(fields[i].Offset);

                // Define a new object to hold our data.
                object value;

                // Check which type the current value is.
                switch (fields[i].Type)
                {
                case JFieldType.INTEGER:
                    // Read the data as a integer.
                    value = ((br.ReadS32() & fields[i].Bitmask) >> fields[i].Shift);
                    break;

                case JFieldType.STRING:
                    // Read the data as a 32-byte long string.
                    value = br.ReadStr32();
                    break;

                case JFieldType.FLOAT:
                    // Read the data as a float32.
                    value = br.ReadF32();
                    break;

                default:
                    // Something went horribly wrong.
                    throw new InvalidDataException();
                }
                // Set the value of this entry's value's data to the value we just read.
                Values[i] = value;

                // Seek back to the position we saved earlier.
                br.Goto(currentPosition);
            }
        }
Exemple #13
0
        /// <summary>
        /// Read a single shader from BIN.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        public BinShader(DhBinaryReader br)
        {
            // Read Unknown 1.
            Unknown1 = br.Read();

            // Read Unknown 2.
            Unknown2 = br.Read();

            // Read Unknown 3.
            Unknown3 = br.Read();

            // Read Tint.
            Tint = br.ReadS32();

            // Read Unknown 4. (Padding)
            Unknown4 = br.Read();

            // Define a new array to hold the Material Indices.
            MaterialIndices = new short[8];

            // Loop through Material Indices.
            for (int i = 0; i < 8; i++)
            {
                // Read a material index and store it in Material Indices array.
                MaterialIndices[i] = br.ReadS16();
            }

            // Define a new array to hold Unknown 5. (Indices?)
            Unknown5 = new short[8];

            // Loop through Unknown 5.
            for (int i = 0; i < 8; i++)
            {
                // Read a Unknown 5 value and store it in Unknown5 array.
                Unknown5[i] = br.ReadS16();
            }
        }
Exemple #14
0
        /// <summary>
        /// Read a single graph object from BIN.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        /// <param name="graphObjectOffset">Offset to the graph objects.</param>
        public GraphObject(DhBinaryReader br, uint graphObjectOffset) // 112 bytes long
        {
            // Read Parent Index.
            ParentIndex = br.ReadS16();

            // Read Child Index.
            ChildIndex = br.ReadS16();

            // Read Next Index.
            NextIndex = br.ReadS16();

            // Read Previous Index.
            PreviousIndex = br.ReadS16();

            // Read Render Flags.
            RenderFlags = (GraphObjectRenderFlags)br.ReadU16();

            // Unknown 1. (Padding?)
            Unknown1 = br.ReadU16();

            // Read Scale.
            Scale = br.ReadVec3();

            // Read Rotation.
            Rotation = br.ReadVec3();

            // Read Position
            Position = br.ReadVec3();

            // Read Bounding Box Minimum.
            BoundingBoxMinimum = br.ReadVec3();

            // Read Bounding Box Maximum.
            BoundingBoxMaximum = br.ReadVec3();

            // Read Bounding Sphere Radius.
            BoundingSphereRadius = br.ReadF32();

            // Read Parent Index.
            PartCount = br.ReadS16();

            // Unknown 3. (Padding?)
            Unknown3 = br.ReadU16();

            // Read Parent Index.
            PartOffset = br.ReadS32();

            // Unknown 4. (Padding?)
            Unknown4 = br.ReadU32s(7);

            // Initialize a new list to hold parts.
            Parts = new List <BinGraphObjectPart>();

            // Offset to continue reading from.
            long currentPosition = br.Position();

            // Goto graphobject's parts.
            br.Goto(graphObjectOffset + PartOffset);

            // Loop through parts.
            for (int i = 0; i < PartCount; i++)
            {
                // Read part and add it to the list of parts.
                Parts.Add(new BinGraphObjectPart(br));
            }

            // Go back to return offset we saved earlier.
            br.Goto(currentPosition);
        }
Exemple #15
0
        /// <summary>
        /// Decompressing Yay0 compressed data. Full credits for this snippet goes to Daniel McCarthy:
        /// https://github.com/Daniel-McCarthy/Mr-Peeps-Compressor/blob/master/PeepsCompress/PeepsCompress/Algorithm%20Classes/YAY0.cs
        /// </summary>
        /// <param name="stream">Stream containing the Yay0 compressed data.</param>
        /// <returns>Decompressed data as a stream.</returns>
        public static Stream Decompress(Stream stream)
        {
            // Define a binary reader to read with.
            DhBinaryReader br = new DhBinaryReader(stream, DhEndian.Big);

            // Define a list of bytes to hold the decompressed data.
            List <byte> output = new List <byte>();

            // Make sure the magic is "Yay0"
            if (br.ReadU32() != 1499560240)
            {
                throw new Exception("No valid Yay0 signature was found!");
            }
            int decompressedLength = br.ReadS32();
            int compressedOffset   = br.ReadS32();
            int decompressedOffset = br.ReadS32();
            int layoutBitsOffset;

            // Begin decompression.
            while (output.Count < decompressedLength)
            {
                // Define variable to hold the layout byte.
                byte LayoutByte = br.Read();
                // Define variable to hold the individual layout bits.
                BitArray LayoutBits = new BitArray(new byte[1] {
                    LayoutByte
                });

                // Loop through the layout bits.
                for (int i = 7; i > -1 && (output.Count < decompressedLength); i--)
                {
                    // The next layout bit is 1. (Uncompressed data)
                    if (LayoutBits[i] == true)
                    {
                        // Yay0 Non-compressed Data Chunk:
                        // Add one byte from decompressedOffset to decompressedData.

                        // Define variable to hold the current layout bits offset.
                        layoutBitsOffset = (int)stream.Position;

                        // Seek to the compressed data offset.
                        stream.Seek(decompressedOffset, SeekOrigin.Begin);

                        // Read a byte and add it to the list of output bytes.
                        output.Add(br.Read());

                        // Advance the decompressed offset by one byte.
                        decompressedOffset++;

                        // Return to the current layout bits offset.
                        stream.Seek(layoutBitsOffset, SeekOrigin.Begin);
                    }
                    // The next layout bit is 0. (Compressed data)
                    else
                    {
                        // Yay0 Compressed Data Chunk:
                        // Total length is 2 bytes.
                        // 4 bits = Length
                        // 12 bits = Offset

                        // Define variable to hold the current offset.
                        layoutBitsOffset = (int)stream.Position;

                        // Seek to the compressed data offset.
                        stream.Seek(compressedOffset, SeekOrigin.Begin);

                        // Read the first byte of the compressed data.
                        byte byte1 = br.Read();

                        // Read the second byte of the compressed data.
                        byte byte2 = br.Read();

                        // Advance the compressed data offset by 2 (Since we just read 2 bytes)
                        compressedOffset += 2;

                        // Get 4 upper bits of the first byte.
                        byte byte1Upper = (byte)((byte1 & 0x0F));

                        // Get 4 lower bits of the first byte.
                        byte byte1Lower = (byte)((byte1 & 0xF0) >> 4);

                        int finalOffset = ((byte1Upper << 8) | byte2) + 1;
                        int finalLength;

                        // Compressed chunk length is higher than 17.
                        if (byte1Lower == 0)
                        {
                            stream.Seek(decompressedOffset, SeekOrigin.Begin);
                            finalLength = br.Read() + 0x12;

                            // Advance the decompressed offset by one byte.
                            decompressedOffset++;
                        }
                        // Compressed chunk length is lower or equal to 17.
                        else
                        {
                            // The data chunk length is equals to the first byte's 4 lower bits + 2.
                            finalLength = byte1Lower + 2;
                        }

                        // Add data for finalLength iterations.
                        for (int j = 0; j < finalLength; j++)
                        {
                            // Add byte at offset (fileSize - finalOffset) to file.
                            output.Add(output[output.Count - finalOffset]);
                        }

                        // Return to the current layout bits offset.
                        stream.Seek(layoutBitsOffset, SeekOrigin.Begin);
                    }
                }
            }

            // Return decompressed data.
            return(new MemoryStream(output.ToArray()));
        }
Exemple #16
0
        /// <summary>
        /// Reads MP from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the MP data.</param>
        public MP(Stream stream)
        {
            // Define a binary reader to read with.
            DhBinaryReader br = new DhBinaryReader(stream, DhEndian.Big);

            // Read Grid Scale.
            GridScale = new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32());

            // Read Minimum Bounds.
            MinimumBounds = new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32());

            // Read Axis Lengths.
            AxisLengths = new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32());

            // Define new array to hold offsets.
            Offsets = new int[7];

            // Loop through our offsets.
            for (int i = 0; i < 7; i++)
            {
                // Read offset and store it to the offsets array.
                Offsets[i] = br.ReadS32();
            }


            // Go to mp's vertex data offset.
            br.Goto(Offsets[0]);

            // Calculate amount of vertices.
            int verticeCount = (Offsets[1] - Offsets[0]) / 12;

            // Define new list to hold vertices.
            Vertices = new List <Vector3>();

            // Loop through vertices.
            for (int i = 0; i < verticeCount; i++)
            {
                // Read vertex and add it to the vertice list.
                Vertices.Add(new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32()));
            }


            // Go to mp's normals offset.
            br.Goto(Offsets[1]);

            // Calculate amount of normals.
            int normalCount = (Offsets[2] - Offsets[1]) / 12;

            // Define new list to hold normals.
            Normals = new List <Vector3>();

            // Loop through normals.
            for (int i = 0; i < verticeCount; i++)
            {
                // Read normal and add it to the normal list.
                Normals.Add(new Vector3(br.ReadF32(), br.ReadF32(), br.ReadF32()));
            }


            // Go to mp's triangle data offset.
            br.Goto(Offsets[2]);

            // Calculate amount of normals.
            int triangleDataCount = (Offsets[3] - Offsets[2]) / 24;

            // Define new list to hold normals.
            TriangleData = new List <MpTriangleData>();

            // Loop through normals.
            for (int i = 0; i < triangleDataCount; i++)
            {
                // Read normal and add it to the normal list.
                TriangleData.Add(new MpTriangleData(br));
            }


            // Go to mp's triangle group offset.
            br.Goto(Offsets[3]);

            // TODO: Implement reading Triangle Group data.


            // Go to mp's grid index offset.
            br.Goto(Offsets[4]);

            // Calculate amount of grid index entries.
            int gridIndexCount = (Offsets[4] - Offsets[3]) / 8;

            // Define new list to hold grid indices.
            GridIndices = new List <MpGridIndex>();

            // Loop through grid indices.
            for (int i = 0; i < gridIndexCount; i++)
            {
                // Read grid index and add it to the grid indices list.
                GridIndices.Add(new MpGridIndex(br));
            }


            // Go to mp's unknown offset.
            br.Goto(Offsets[5]);

            // TODO: Implement reading Unknown data.
        }
Exemple #17
0
        /// <summary>
        /// Read a single batch from BIN.
        /// </summary>
        /// <param name="br">Binary Reader to use.</param>
        /// <param name="batchesOffset">Offset to batches.</param>
        public BinBatch(DhBinaryReader br, long batchesOffset)
        {
            // Read face count.
            FaceCount = br.ReadU16();

            // Read primitive list size.
            ListSize = (ushort)(br.ReadS16() << 5);

            // Read vertex attributes.
            VertexAttributes = (BinBatchAttributes)br.ReadU32();

            // Read UseNormals flag.
            UseNormals = br.Read();

            // Read Position Winding.
            Positions = br.Read();

            // Read UV Count.
            UvCount = br.Read();

            // Read UseNBT flag.
            UseNBT = br.Read();

            // Read Primitive offset.
            PrimitiveOffset = br.ReadU32();

            // Define array to hold Unknown 1 values.
            Unknown1 = new int[2];

            // Loop through Unknown 1 values.
            for (int i = 0; i < 2; i++)
            {
                // Read current Unknown 1 value.
                Unknown1[i] = br.ReadS32();
            }

            // Save the current position.
            long currentPosition = br.Position();

            // Go to the bin batches offset.
            br.Goto(batchesOffset);

            // Sail to the batches's primitive offset.
            br.Sail(PrimitiveOffset);

            // Define list to hold batch's primitives.
            Primitives = new List <BinPrimitive>();

            // Define int to hold amount of faces read.
            int readFaces = 0;

            // Read primitives until batch's face count has been reached.
            while (readFaces < FaceCount && br.Position() < (batchesOffset + PrimitiveOffset + ListSize))
            {
                // Read primitive.
                BinPrimitive binPrimitive = new BinPrimitive(br, UseNBT, UvCount, VertexAttributes);

                // Add the primitive to the batch's primitives.
                Primitives.Add(binPrimitive);

                // Add primitive's face count to the read faces counter.
                readFaces += binPrimitive.FaceCount;
            }

            // Go to the previously saved offset.
            br.Goto(currentPosition);
        }
Exemple #18
0
        /// <summary>
        /// Reads MP from a byte array.
        /// </summary>
        /// <param name="data">The byte array containing the MP data.</param>
        public MP(byte[] data)
        {
            // Define a binary reader to read with.
            DhBinaryReader br = new DhBinaryReader(data, DhEndian.Big);

            // Read Grid Scale.
            GridScale = br.ReadVec3();

            // Read Minimum Bounds.
            MinimumBounds = br.ReadVec3();

            // Read Axis Lengths.
            AxisLengths = br.ReadVec3();

            // Define new array to hold offsets.
            Offsets = new int[7];

            // Loop through our offsets.
            for (int i = 0; i < 7; i++)
            {
                // Read offset and store it to the offsets array.
                Offsets[i] = br.ReadS32();
            }


            // Go to mp's vertex data offset.
            br.Goto(Offsets[0]);

            // Calculate amount of vertices.
            int verticeCount = (Offsets[1] - Offsets[0]) / 12;

            // Define new list to hold vertices.
            Vertices = new List <Vec3>();

            // Loop through vertices.
            for (int i = 0; i < verticeCount; i++)
            {
                // Read vertex and add it to the list of vertices.
                Vertices.Add(br.ReadVec3());
            }


            // Go to mp's normals offset.
            br.Goto(Offsets[1]);

            // Calculate amount of normals.
            int normalCount = (Offsets[2] - Offsets[1]) / 12;

            // Define new list to hold normals.
            Normals = new List <Vec3>();

            // Loop through normals.
            for (int i = 0; i < normalCount; i++)
            {
                // Read normal and add it to the normal list.
                Normals.Add(br.ReadVec3());
            }


            // Go to mp's triangle data offset.
            br.Goto(Offsets[2]);

            // Calculate amount of triangles.
            int triangleDataCount = (Offsets[3] - Offsets[2]) / 24;

            // Define new list to hold triangle data.
            TriangleData = new List <TriangleData>();

            // Loop through triangles.
            for (int i = 0; i < triangleDataCount; i++)
            {
                // Read triangle and add it to the triangle data list.
                TriangleData.Add(new TriangleData(br));
            }


            // Go to mp's triangle group offset.
            br.Goto(Offsets[3]);

            // Define new list to hold triangle groups.
            TriangleGroups = new List <TriangleGroup>();

            // Make sure first ushort is 0xFFFF.
            if (br.ReadU16() != 0xFFFF)
            {
                throw new FormatException("Start of triangle groups section was not 0xFFFF!");
            }

            // We'll read triangle groups as long as we're not entering the next section.
            while (br.Position() < Offsets[4] - 2)
            {
                // Read group and add it to the groups list.
                TriangleGroups.Add(new TriangleGroup(br));
            }

            // Make sure last ushort is 0xFFFF.
            if (br.ReadU16() != 0xFFFF)
            {
                throw new FormatException("End of triangle groups section was not 0xFFFF!");
            }

            // Go to mp's grid index offset.
            br.Goto(Offsets[4]);

            // Calculate amount of grid index entries. (Offset 5 is a duplicate of offset 4)
            int gridIndexCount = (Offsets[6] - Offsets[4]) / 8;

            // Define new list to hold grid indices.
            GridIndices = new List <GridIndex>();

            // Loop through grid indices.
            for (int i = 0; i < gridIndexCount; i++)
            {
                GridIndices.Add(new GridIndex(br));
            }


            // Go to mp's unknown offset.
            br.Goto(Offsets[6]);

            // Define new list to hold unknown data.
            Unknowns = new List <Unknown>();

            // We'll read unknowns as long as we're not reading padding EOF.
            while (br.Position() < br.GetStream().Length)
            {
                // Check if next byte is 0xFF. (More data)
                if (br.Read() == 0xFF)
                {
                    // Jump back a byte, since we checked for data.
                    br.Sail(-1);

                    // Read unknown and add it to the unknowns list.
                    Unknowns.Add(new Unknown(br));
                }
                else
                {
                    // We've reached padding, stop reading.
                    break;
                }
            }
        }