コード例 #1
0
        private ModelObjectFlags PeekFlags(BinaryReader br)
        {
            long initialPosition = br.BaseStream.Position;

            // Skip ahead to the flag block
            br.BaseStream.Position += 16;

            ModelObjectFlags flags = (ModelObjectFlags)br.ReadUInt32();

            // Seek back to the initial position
            br.BaseStream.Position = initialPosition;

            return(flags);
        }
コード例 #2
0
ファイル: MDX.cs プロジェクト: westerjn/libwarcraft
        private void LoadFromStream(Stream dataStream)
        {
            using (BinaryReader br = new BinaryReader(dataStream))
            {
                string dataSignature = new string(br.ReadBinarySignature().Reverse().ToArray());
                if (dataSignature != Signature)
                {
                    throw new ArgumentException("The provided data stream does not contain a valid MDX signature. " +
                                                "It might be a Legion file, or you may have omitted the signature, which should be \"MD20\".");
                }

                this.Version          = GetModelVersion(br.ReadUInt32());
                this.Name             = new string(br.ReadMDXArray <char>().GetValues().ToArray());
                this.GlobalModelFlags = (ModelObjectFlags)br.ReadUInt32();

                this.GlobalSequenceTimestamps     = br.ReadMDXArray <uint>();
                this.AnimationSequences           = br.ReadMDXArray <MDXAnimationSequence>(this.Version);
                this.AnimationSequenceLookupTable = br.ReadMDXArray <ushort>();

                if (this.Version < WarcraftVersion.Wrath)
                {
                    this.PlayableAnimationLookupTable = br.ReadMDXArray <MDXPlayableAnimationLookupTableEntry>();
                }

                this.Bones = br.ReadMDXArray <MDXBone>(this.Version);
                this.BoneSocketLookupTable = br.ReadMDXArray <ushort>();
                this.Vertices = br.ReadMDXArray <MDXVertex>();

                if (this.Version < WarcraftVersion.Wrath)
                {
                    this.Skins = br.ReadMDXArray <MDXSkin>(this.Version);
                }
                else
                {
                    // Skins are stored out of file, figure out a clean solution
                    this.SkinCount = br.ReadUInt32();
                }

                this.ColourAnimations       = br.ReadMDXArray <MDXColourAnimation>(this.Version);
                this.Textures               = br.ReadMDXArray <MDXTexture>();
                this.TransparencyAnimations = br.ReadMDXArray <MDXTextureWeight>(this.Version);

                if (this.Version <= WarcraftVersion.BurningCrusade)
                {
                    // There's an array of something here, but we've no idea what type of data it is. Thus, we'll skip
                    // over it.
                    br.BaseStream.Position += 8;
                }

                this.TextureTransformations        = br.ReadMDXArray <MDXTextureTransform>(this.Version);
                this.ReplaceableTextureLookupTable = br.ReadMDXArray <short>();
                this.Materials = br.ReadMDXArray <MDXMaterial>(this.Version);

                this.BoneLookupTable                  = br.ReadMDXArray <short>();
                this.TextureLookupTable               = br.ReadMDXArray <short>();
                this.TextureMappingLookupTable        = br.ReadMDXArray <EMDXTextureMappingType>();
                this.TransparencyLookupTable          = br.ReadMDXArray <short>();
                this.TextureTransformationLookupTable = br.ReadMDXArray <short>();

                this.BoundingBox          = br.ReadBox();
                this.BoundingSphereRadius = br.ReadSingle();

                this.CollisionBox          = br.ReadBox();
                this.CollisionSphereRadius = br.ReadSingle();

                this.CollisionTriangles = br.ReadMDXArray <ushort>();
                this.CollisionVertices  = br.ReadMDXArray <Vector3>();
                this.CollisionNormals   = br.ReadMDXArray <Vector3>();

                this.Attachments           = br.ReadMDXArray <MDXAttachment>(this.Version);
                this.AttachmentLookupTable = br.ReadMDXArray <MDXAttachmentType>();

                this.AnimationEvents = br.ReadMDXArray <MDXAnimationEvent>(this.Version);
                this.Lights          = br.ReadMDXArray <MDXLight>(this.Version);

                this.Cameras = br.ReadMDXArray <MDXCamera>(this.Version);
                this.CameraTypeLookupTable = br.ReadMDXArray <MDXCameraType>();

                this.RibbonEmitters = br.ReadMDXArray <MDXRibbonEmitter>(this.Version);

                // TODO: Particle Emitters
                // Skip for now
                br.BaseStream.Position += 8;

                if (this.Version >= WarcraftVersion.Wrath && this.GlobalModelFlags.HasFlag(ModelObjectFlags.HasBlendModeOverrides))
                {
                    this.BlendMapOverrides = br.ReadMDXArray <BlendingMode>();
                }
            }
        }
コード例 #3
0
        public MDXHeader(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    string Signature = new string(br.ReadChars(4));
                    if (Signature != MDXHeader.Signature)
                    {
                        throw new ArgumentException("The provided data stream does not contain a valid MDX signature. " +
                                                    "It might be a Legion file, or you may have omitted the signature, which should be \"MD20\".");
                    }

                    this.Version                        = br.ReadUInt32();
                    this.NameLength                     = br.ReadUInt32();
                    this.NameOffset                     = br.ReadUInt32();
                    this.GlobalModelFlags               = (ModelObjectFlags)br.ReadUInt32();
                    this.GlobalSequenceCount            = br.ReadUInt32();
                    this.GlobalSequencesOffset          = br.ReadUInt32();
                    this.AnimationSequenceCount         = br.ReadUInt32();
                    this.AnimationSequencesOffset       = br.ReadUInt32();
                    this.AnimationLookupTableEntryCount = br.ReadUInt32();
                    this.AnimationLookupTableOffset     = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.PlayableAnimationLookupTableEntryCount = br.ReadUInt32();
                        this.PlayableAnimationLookupTableOffset     = br.ReadUInt32();
                    }

                    this.BoneCount   = br.ReadUInt32();
                    this.BonesOffset = br.ReadUInt32();
                    this.KeyedBoneLookupTableCount   = br.ReadUInt32();
                    this.KeyedBoneLookupTablesOffset = br.ReadUInt32();

                    this.VertexCount    = br.ReadUInt32();
                    this.VerticesOffset = br.ReadUInt32();
                    this.LODViewsCount  = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.LODViewsOffset = br.ReadUInt32();
                    }

                    this.SubmeshColourAnimationCount   = br.ReadUInt32();
                    this.SubmeshColourAnimationsOffset = br.ReadUInt32();
                    this.TextureCount                 = br.ReadUInt32();
                    this.TexturesOffset               = br.ReadUInt32();
                    this.TransparencyAnimationCount   = br.ReadUInt32();
                    this.TransparencyAnimationsOffset = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.UnknownCount  = br.ReadUInt32();
                        this.UnknownOffset = br.ReadUInt32();
                    }

                    this.UVTextureAnimationCount   = br.ReadUInt32();
                    this.UVTextureAnimationsOffset = br.ReadUInt32();
                    this.ReplaceableTextureCount   = br.ReadUInt32();
                    this.ReplaceableTexturesOffset = br.ReadUInt32();
                    this.RenderFlagCount           = br.ReadUInt32();
                    this.RenderFlagsOffset         = br.ReadUInt32();

                    this.BoneLookupTableCount                 = br.ReadUInt32();
                    this.BoneLookupTablesOffset               = br.ReadUInt32();
                    this.TextureLookupTableCount              = br.ReadUInt32();
                    this.TextureLookupTablesOffset            = br.ReadUInt32();
                    this.TextureUnitCount                     = br.ReadUInt32();
                    this.TextureUnitsOffset                   = br.ReadUInt32();
                    this.TransparencyLookupTableCount         = br.ReadUInt32();
                    this.TransparencyLookupTablesOffset       = br.ReadUInt32();
                    this.UVTextureAnimationLookupTableCount   = br.ReadUInt32();
                    this.UVTextureAnimationLookupTablesOffset = br.ReadUInt32();

                    this.BoundingBox          = br.ReadBox();
                    this.BoundingSphereRadius = br.ReadSingle();

                    this.CollisionBox          = br.ReadBox();
                    this.CollisionSphereRadius = br.ReadSingle();

                    this.BoundingTriangleCount   = br.ReadUInt32();
                    this.BoundingTrianglesOffset = br.ReadUInt32();
                    this.BoundingVertexCount     = br.ReadUInt32();
                    this.BoundingVerticesOffset  = br.ReadUInt32();
                    this.BoundingNormalCount     = br.ReadUInt32();
                    this.BoundingNormalsOffset   = br.ReadUInt32();

                    this.AttachmentsCount              = br.ReadUInt32();
                    this.AttachmentsOffset             = br.ReadUInt32();
                    this.AttachmentsLookupTableCount   = br.ReadUInt32();
                    this.AttachmentsLookupTablesOffset = br.ReadUInt32();

                    this.AnimationEventCount      = br.ReadUInt32();
                    this.AnimationEventsOffset    = br.ReadUInt32();
                    this.LightCount               = br.ReadUInt32();
                    this.LightsOffset             = br.ReadUInt32();
                    this.CameraCount              = br.ReadUInt32();
                    this.CamerasOffset            = br.ReadUInt32();
                    this.CameraLookupTableCount   = br.ReadUInt32();
                    this.CameraLookupTablesOffset = br.ReadUInt32();

                    this.RibbonEmitterCount     = br.ReadUInt32();
                    this.RibbonEmittersOffset   = br.ReadUInt32();
                    this.ParticleEmitterCount   = br.ReadUInt32();
                    this.ParticleEmittersOffset = br.ReadUInt32();

                    if (this.GlobalModelFlags.HasFlag(ModelObjectFlags.HasBlendModeOverrides))
                    {
                        this.BlendMapCount   = br.ReadUInt32();
                        this.BlendMapsOffset = br.ReadUInt32();
                    }
                }
            }
        }
コード例 #4
0
ファイル: MDXHeader.cs プロジェクト: Nihlus/libwarcraft
        public MDXHeader(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    string Signature = new string(br.ReadChars(4));
                    if (Signature != MDXHeader.Signature)
                    {
                        throw new ArgumentException("The provided data stream does not contain a valid MDX signature. " +
                            "It might be a Legion file, or you may have omitted the signature, which should be \"MD20\".");
                    }

                    this.Version = br.ReadUInt32();
                    this.NameLength = br.ReadUInt32();
                    this.NameOffset = br.ReadUInt32();
                    this.GlobalModelFlags = (ModelObjectFlags)br.ReadUInt32();
                    this.GlobalSequenceCount = br.ReadUInt32();
                    this.GlobalSequencesOffset = br.ReadUInt32();
                    this.AnimationSequenceCount = br.ReadUInt32();
                    this.AnimationSequencesOffset = br.ReadUInt32();
                    this.AnimationLookupTableEntryCount = br.ReadUInt32();
                    this.AnimationLookupTableOffset = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.PlayableAnimationLookupTableEntryCount = br.ReadUInt32();
                        this.PlayableAnimationLookupTableOffset = br.ReadUInt32();
                    }

                    this.BoneCount = br.ReadUInt32();
                    this.BonesOffset = br.ReadUInt32();
                    this.KeyedBoneLookupTableCount = br.ReadUInt32();
                    this.KeyedBoneLookupTablesOffset = br.ReadUInt32();

                    this.VertexCount = br.ReadUInt32();
                    this.VerticesOffset = br.ReadUInt32();
                    this.LODViewsCount = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.LODViewsOffset = br.ReadUInt32();
                    }

                    this.SubmeshColourAnimationCount = br.ReadUInt32();
                    this.SubmeshColourAnimationsOffset = br.ReadUInt32();
                    this.TextureCount = br.ReadUInt32();
                    this.TexturesOffset = br.ReadUInt32();
                    this.TransparencyAnimationCount = br.ReadUInt32();
                    this.TransparencyAnimationsOffset = br.ReadUInt32();

                    if (GetModelVersion(this.Version) < WarcraftVersion.Wrath)
                    {
                        this.UnknownCount = br.ReadUInt32();
                        this.UnknownOffset = br.ReadUInt32();
                    }

                    this.UVTextureAnimationCount = br.ReadUInt32();
                    this.UVTextureAnimationsOffset = br.ReadUInt32();
                    this.ReplaceableTextureCount = br.ReadUInt32();
                    this.ReplaceableTexturesOffset = br.ReadUInt32();
                    this.RenderFlagCount = br.ReadUInt32();
                    this.RenderFlagsOffset = br.ReadUInt32();

                    this.BoneLookupTableCount = br.ReadUInt32();
                    this.BoneLookupTablesOffset = br.ReadUInt32();
                    this.TextureLookupTableCount = br.ReadUInt32();
                    this.TextureLookupTablesOffset = br.ReadUInt32();
                    this.TextureUnitCount = br.ReadUInt32();
                    this.TextureUnitsOffset = br.ReadUInt32();
                    this.TransparencyLookupTableCount = br.ReadUInt32();
                    this.TransparencyLookupTablesOffset = br.ReadUInt32();
                    this.UVTextureAnimationLookupTableCount = br.ReadUInt32();
                    this.UVTextureAnimationLookupTablesOffset = br.ReadUInt32();

                    this.BoundingBox = br.ReadBox();
                    this.BoundingSphereRadius = br.ReadSingle();

                    this.CollisionBox = br.ReadBox();
                    this.CollisionSphereRadius = br.ReadSingle();

                    this.BoundingTriangleCount = br.ReadUInt32();
                    this.BoundingTrianglesOffset = br.ReadUInt32();
                    this.BoundingVertexCount = br.ReadUInt32();
                    this.BoundingVerticesOffset = br.ReadUInt32();
                    this.BoundingNormalCount = br.ReadUInt32();
                    this.BoundingNormalsOffset = br.ReadUInt32();

                    this.AttachmentsCount = br.ReadUInt32();
                    this.AttachmentsOffset = br.ReadUInt32();
                    this.AttachmentsLookupTableCount = br.ReadUInt32();
                    this.AttachmentsLookupTablesOffset = br.ReadUInt32();

                    this.AnimationEventCount = br.ReadUInt32();
                    this.AnimationEventsOffset = br.ReadUInt32();
                    this.LightCount = br.ReadUInt32();
                    this.LightsOffset = br.ReadUInt32();
                    this.CameraCount = br.ReadUInt32();
                    this.CamerasOffset = br.ReadUInt32();
                    this.CameraLookupTableCount = br.ReadUInt32();
                    this.CameraLookupTablesOffset = br.ReadUInt32();

                    this.RibbonEmitterCount = br.ReadUInt32();
                    this.RibbonEmittersOffset = br.ReadUInt32();
                    this.ParticleEmitterCount = br.ReadUInt32();
                    this.ParticleEmittersOffset = br.ReadUInt32();

                    if (this.GlobalModelFlags.HasFlag(ModelObjectFlags.HasBlendModeOverrides))
                    {
                        this.BlendMapCount = br.ReadUInt32();
                        this.BlendMapsOffset = br.ReadUInt32();
                    }
                }
            }
        }
コード例 #5
0
        public MDX(Stream MDXStream)
        {
            using (BinaryReader br = new BinaryReader(MDXStream))
            {
                // Read Wrath header or read pre-wrath header
                WarcraftVersion Format = PeekFormat(br);
                if (Format < WarcraftVersion.Wrath)
                {
                    this.Header = new MDXHeader(br.ReadBytes(324));
                }
                else
                {
                    ModelObjectFlags Flags = PeekFlags(br);
                    if (Flags.HasFlag(ModelObjectFlags.HasBlendModeOverrides))
                    {
                        this.Header = new MDXHeader(br.ReadBytes(308));
                    }
                    else
                    {
                        this.Header = new MDXHeader(br.ReadBytes(312));
                    }
                }

                // Seek and read model name
                br.BaseStream.Position = this.Header.NameOffset;
                this.Name = new string(br.ReadChars((int)this.Header.NameLength));

                // Seek to Global Sequences
                br.BaseStream.Position = this.Header.GlobalSequencesOffset;
                for (int i = 0; i < this.Header.GlobalSequenceCount; ++i)
                {
                    this.GlobalSequenceTimestamps.Add(br.ReadUInt32());
                }

                // Seek to Animation Sequences
                br.BaseStream.Position = this.Header.AnimationSequencesOffset;
                int sequenceSize = MDXAnimationSequence.GetSize();
                for (int i = 0; i < this.Header.AnimationSequenceCount; ++i)
                {
                    this.AnimationSequences.Add(new MDXAnimationSequence(br.ReadBytes(sequenceSize)));
                }

                // Seek to Animation Sequence Lookup Table
                br.BaseStream.Position = this.Header.AnimationLookupTableOffset;
                for (int i = 0; i < this.Header.AnimationLookupTableEntryCount; ++i)
                {
                    this.AnimationSequenceLookupTable.Add(br.ReadInt16());
                }

                if (MDXHeader.GetModelVersion(this.Header.Version) < WarcraftVersion.Wrath)
                {
                    // Seek to Playable Animations Lookup Table
                    br.BaseStream.Position = this.Header.PlayableAnimationLookupTableOffset;
                    for (int i = 0; i < this.Header.PlayableAnimationLookupTableEntryCount; ++i)
                    {
                        this.PlayableAnimationLookupTable.Add(new MDXPlayableAnimationLookupTableEntry(br.ReadBytes(4)));
                    }
                }

                // Seek to bone block
                br.BaseStream.Position = this.Header.BonesOffset;
                for (int i = 0; i < this.Header.BoneCount; ++i)
                {
                    // TODO: properly skip to the next bone record, data is not aligned
                    MDXBone Bone = new MDXBone();

                    Bone.AnimationID = br.ReadInt32();
                    Bone.Flags       = (MDXBoneFlags)br.ReadUInt32();
                    Bone.ParentBone  = br.ReadInt16();
                    Bone.SubmeshID   = br.ReadUInt16();

                    if (MDXHeader.GetModelVersion(this.Header.Version) >= WarcraftVersion.BurningCrusade)
                    {
                        Bone.Unknown1 = br.ReadUInt16();
                        Bone.Unknown1 = br.ReadUInt16();
                    }

                    // TODO: Rework animation track reading
                    // Read bone animation header block
                    //Bone.AnimatedTranslation = new MDXTrack<Vector3f>(br, MDXHeader.GetModelVersion(Header.Version));
                    //Bone.AnimatedRotation = new MDXTrack<Quaternion>(br, MDXHeader.GetModelVersion(Header.Version));
                    //Bone.AnimatedScale = new MDXTrack<Vector3f>(br, MDXHeader.GetModelVersion(Header.Version));

                    Bone.PivotPoint = br.ReadVector3f();

                    this.Bones.Add(Bone);
                }

                /*
                 * // Read bone animation data
                 * foreach (MDXBone Bone in Bones)
                 * {
                 *      // Read animation translation block
                 *      br.BaseStream.Position = Bone.AnimatedTranslation.Values.ElementsOffset;
                 *      for (int j = 0; j < Bone.AnimatedTranslation.Values.Count; ++j)
                 *      {
                 *              Bone.AnimatedTranslation.Values.Add(br.ReadVector3f());
                 *      }
                 *
                 *      // Read animation rotation block
                 *      br.BaseStream.Position = Bone.AnimatedRotation.ValuesOffset;
                 *      for (int j = 0; j < Bone.AnimatedRotation.ValueCount; ++j)
                 *      {
                 *              if (MDXHeader.GetModelVersion(Header.Version) > MDXFormat.Classic)
                 *              {
                 *                      Bone.AnimatedRotation.Values.Add(br.ReadQuaternion16());
                 *              }
                 *              else
                 *              {
                 *                      Bone.AnimatedRotation.Values.Add(br.ReadQuaternion32());
                 *              }
                 *      }
                 *
                 *      // Read animation scale block
                 *      br.BaseStream.Position = Bone.AnimatedScale.ValuesOffset;
                 *      for (int j = 0; j < Bone.AnimatedScale.ValueCount; ++j)
                 *      {
                 *              Bone.AnimatedScale.Values.Add(br.ReadVector3f());
                 *      }
                 * }
                 */

                // Seek to Skeletal Bone Lookup Table
                br.BaseStream.Position = this.Header.KeyedBoneLookupTablesOffset;
                for (int i = 0; i < this.Header.KeyedBoneLookupTableCount; ++i)
                {
                    this.KeyedBoneLookupTable.Add(br.ReadInt16());
                }

                // Seek to vertex block
                br.BaseStream.Position = this.Header.VerticesOffset;
                for (int i = 0; i < this.Header.VertexCount; ++i)
                {
                    this.Vertices.Add(new MDXVertex(br.ReadBytes(48)));
                }

                // Seek to view block
                if (MDXHeader.GetModelVersion(this.Header.Version) < WarcraftVersion.Wrath)
                {
                    br.BaseStream.Position = this.Header.LODViewsOffset;

                    // Read the view headers
                    for (int i = 0; i < this.Header.LODViewsCount; ++i)
                    {
                        MDXViewHeader ViewHeader = new MDXViewHeader(br.ReadBytes(44));

                        MDXView View = new MDXView();
                        View.Header = ViewHeader;

                        this.LODViews.Add(View);
                    }

                    // Read view data
                    foreach (MDXView View in this.LODViews)
                    {
                        // Read view vertex indices
                        View.VertexIndices     = new List <ushort>();
                        br.BaseStream.Position = View.Header.VertexIndicesOffset;
                        for (int j = 0; j < View.Header.VertexIndexCount; ++j)
                        {
                            View.VertexIndices.Add(br.ReadUInt16());
                        }

                        // Read view triangles
                        View.Triangles         = new List <MDXTriangle>();
                        br.BaseStream.Position = View.Header.TriangleVertexIndicesOffset;
                        for (int j = 0; j < View.Header.TriangleVertexCount / 3; ++j)
                        {
                            MDXTriangle Triangle = new MDXTriangle(br.ReadUInt16(), br.ReadUInt16(), br.ReadUInt16());

                            View.Triangles.Add(Triangle);
                        }

                        // Read view vertex properties
                        View.VertexProperties  = new List <MDXVertexProperty>();
                        br.BaseStream.Position = View.Header.VertexPropertiesOffset;
                        for (int j = 0; j < View.Header.VertexPropertyCount; ++j)
                        {
                            View.VertexProperties.Add(new MDXVertexProperty(br.ReadByte(), br.ReadByte(), br.ReadByte(), br.ReadByte()));
                        }

                        // Read view submeshes
                        View.Submeshes         = new List <MDXSubmesh>();
                        br.BaseStream.Position = View.Header.SubmeshesOffset;
                        for (int j = 0; j < View.Header.SubmeshCount; ++j)
                        {
                            byte[] submeshData;
                            if (MDXHeader.GetModelVersion(this.Header.Version) >= WarcraftVersion.BurningCrusade)
                            {
                                submeshData = br.ReadBytes(48);
                            }
                            else
                            {
                                submeshData = br.ReadBytes(32);
                            }

                            View.Submeshes.Add(new MDXSubmesh(submeshData));
                        }

                        View.TextureUnits      = new List <MDXTextureUnit>();
                        br.BaseStream.Position = View.Header.TexturesOffset;
                        for (int j = 0; j < View.Header.TextureCount; ++j)
                        {
                            View.TextureUnits.Add(new MDXTextureUnit(br.ReadBytes(24)));
                        }
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }

                /*
                 * // TODO: Rework animation track reading
                 * // Seek to submesh animation block
                 * br.BaseStream.Position = Header.SubmeshColourAnimationsOffset;
                 * for (int i = 0; i < Header.SubmeshColourAnimationCount; ++i)
                 * {
                 *      MDXTrack<RGB> ColourTrack = new MDXTrack<RGB>(br, MDXHeader.GetModelVersion(Header.Version));
                 *      MDXTrack<short> OpacityTrack = new MDXTrack<short>(br, MDXHeader.GetModelVersion(Header.Version));
                 *
                 *      MDXSubmeshColourAnimation ColourAnimation = new MDXSubmeshColourAnimation();
                 *      ColourAnimation.ColourTrack = ColourTrack;
                 *      ColourAnimation.OpacityTrack = OpacityTrack;
                 *
                 *      ColourAnimations.Add(ColourAnimation);
                 * }
                 * // Read submesh animation values
                 * foreach (MDXSubmeshColourAnimation ColourAnimation in ColourAnimations)
                 * {
                 *      // Read the colour track
                 *      br.BaseStream.Position = ColourAnimation.ColourTrack.ValuesOffset;
                 *      for (int j = 0; j < ColourAnimation.ColourTrack.ValueCount; ++j)
                 *      {
                 *              ColourAnimation.ColourTrack.Values.Add(new RGB(br.ReadVector3f()));
                 *      }
                 *
                 *      // Read the opacity track
                 *      br.BaseStream.Position = ColourAnimation.OpacityTrack.ValuesOffset;
                 *      for (int j = 0; j < ColourAnimation.OpacityTrack.ValueCount; ++j)
                 *      {
                 *              ColourAnimation.OpacityTrack.Values.Add(br.ReadInt16());
                 *      }
                 * }
                 */

                // TODO: Use this pattern for the tracks as well, where values are outreferenced
                // from the block
                // Seek to Texture definition block
                br.BaseStream.Position = this.Header.TexturesOffset;
                for (int i = 0; i < this.Header.TextureCount; ++i)
                {
                    MDXTexture Texture = new MDXTexture(br.ReadBytes(16));
                    this.Textures.Add(Texture);
                }

                // Read the texture definition strings
                foreach (MDXTexture Texture in this.Textures)
                {
                    br.BaseStream.Position = Texture.FilenameOffset;
                    Texture.Filename       = new string(br.ReadChars((int)Texture.FilenameLength));
                }

                /*
                 * // TODO: Rework animation track reading
                 * // Seek to transparency block
                 * br.BaseStream.Position = Header.TransparencyAnimationsOffset;
                 * for (int i = 0; i < Header.TransparencyAnimationCount; ++i)
                 * {
                 *      TransparencyAnimations.Add(new MDXTrack<short>(br, MDXHeader.GetModelVersion(Header.Version)));
                 * }
                 * // Read transparency animation block data
                 * foreach (MDXTrack<short> TransparencyTrack in TransparencyAnimations)
                 * {
                 *      // Read the opacity track
                 *      br.BaseStream.Position = TransparencyTrack.ValuesOffset;
                 *      for (int j = 0; j < TransparencyTrack.ValueCount; ++j)
                 *      {
                 *              TransparencyTrack.Values.Add(br.ReadInt16());
                 *      }
                 * }
                 *
                 * // TODO: Rework animation track reading
                 * // UV Animations
                 * br.BaseStream.Position = Header.UVTextureAnimationsOffset;
                 * for (int i = 0; i < Header.UVTextureAnimationCount; ++i)
                 * {
                 *      br.BaseStream.Position = Header.UVTextureAnimationsOffset + (i * 84);
                 *
                 *      MDXUVAnimation UVAnimation = new MDXUVAnimation();
                 *      UVAnimation.TranslationTrack = new MDXTrack<Vector3f>(br, MDXHeader.GetModelVersion(Header.Version));
                 *      UVAnimation.RotationTrack = new MDXTrack<Quaternion>(br, MDXHeader.GetModelVersion(Header.Version));
                 *      UVAnimation.ScaleTrack = new MDXTrack<Vector3f>(br, MDXHeader.GetModelVersion(Header.Version));
                 *
                 *      UVAnimations.Add(UVAnimation);
                 * }
                 * // Read UV animation track data
                 * foreach (MDXUVAnimation UVAnimation in UVAnimations)
                 * {
                 *      // Read animation translation block
                 *      br.BaseStream.Position = UVAnimation.TranslationTrack.ValuesOffset;
                 *      for (int j = 0; j < UVAnimation.TranslationTrack.ValueCount; ++j)
                 *      {
                 *              UVAnimation.TranslationTrack.Values.Add(br.ReadVector3f());
                 *      }
                 *
                 *      // Read animation rotation block
                 *      br.BaseStream.Position = UVAnimation.RotationTrack.ValuesOffset;
                 *      for (int j = 0; j < UVAnimation.RotationTrack.ValueCount; ++j)
                 *      {
                 *              if (MDXHeader.GetModelVersion(Header.Version) > MDXFormat.Classic)
                 *              {
                 *                      UVAnimation.RotationTrack.Values.Add(br.ReadQuaternion16());
                 *              }
                 *              else
                 *              {
                 *                      UVAnimation.RotationTrack.Values.Add(br.ReadQuaternion32());
                 *              }
                 *      }
                 *
                 *      // Read animation scale block
                 *      br.BaseStream.Position = UVAnimation.ScaleTrack.ValuesOffset;
                 *      for (int j = 0; j < UVAnimation.ScaleTrack.ValueCount; ++j)
                 *      {
                 *              UVAnimation.ScaleTrack.Values.Add(br.ReadVector3f());
                 *      }
                 * }
                 */

                // Replaceable textures

                // Render flags
                // Seek to render flag block
                br.BaseStream.Position = this.Header.RenderFlagsOffset;
                for (int i = 0; i < this.Header.RenderFlagCount; ++i)
                {
                    this.RenderFlags.Add(new MDXRenderFlagPair(br.ReadBytes(4)));
                }

                // Bone lookup

                // Texture lookup

                // Texture unit lookup
                // Seek to texture unit lookup block
                br.BaseStream.Position = this.Header.TextureUnitsOffset;
                for (int i = 0; i < this.Header.TextureUnitCount; ++i)
                {
                    this.TextureUnitLookupTable.Add(br.ReadInt16());
                }

                // Transparency lookup
                // Seek to transparency lookup table
                br.BaseStream.Position = this.Header.TransparencyLookupTablesOffset;
                for (int i = 0; i < this.Header.TransparencyLookupTableCount; ++i)
                {
                    this.TransparencyLookupTable.Add(br.ReadInt16());
                }

                // UV animation lookup

                // Bounding box

                // Bounding radius

                // Collision box

                // Collision radius

                // Bounding tris

                // Bounding verts

                // Bounding normals

                // Attachments

                // Attachment lookup

                // Anim notifies (events)

                // Lights

                // Cameras

                // Camera lookup

                // Ribbon Emitters

                // Particle Emitters

                // Blend maps (if flags say they exist)
            }
        }