/// <summary>
        /// Reads the data from a compressed track
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        private object[] ReadCompressed(SsbhParser reader, uint flags)
        {
            List <object> output = new List <object>();

            uint dataOffset = (uint)reader.BaseStream.Position;
            SsbhAnimCompressedHeader header = reader.ByteToType <SsbhAnimCompressedHeader>();

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Boolean))
            {
                ReadBooleans(reader, output, dataOffset, header);
            }
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Texture))
            {
                // TODO: What type is this
            }
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Float))
            {
                //TODO: What type is this
            }
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.PatternIndex))
            {
                //TODO: What type is this
            }
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Vector4))
            {
                ReadVector4(reader, output, dataOffset, header);
            }
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Transform))
            {
                ReadTransform(reader, output, dataOffset, header);
            }

            return(output.ToArray());
        }
        /// <summary>
        /// Decompresses values in a track
        /// </summary>
        /// <param name="parser"></param>
        /// <param name="dataOffset"></param>
        /// <param name="header"></param>
        /// <param name="valueCount"></param>
        /// <returns></returns>
        private List <float[]> DecompressValues(SsbhParser parser, uint dataOffset, SsbhAnimCompressedHeader header, int valueCount)
        {
            List <float[]> transforms = new List <float[]>(header.FrameCount);

            // PreProcess
            SsbhAnimCompressedItem[] items = parser.ByteToType <SsbhAnimCompressedItem>(valueCount);

            parser.Seek(dataOffset + header.DefaultDataOffset);

            float[] defaultValues = GetDefaultValues(parser, valueCount);

            parser.Seek(dataOffset + header.CompressedDataOffset);
            for (int frameIndex = 0; frameIndex < header.FrameCount; frameIndex++)
            {
                // Copy default values.
                float[] values = new float[valueCount];
                for (int i = 0; i < valueCount; i++)
                {
                    values[i] = defaultValues[i];
                }

                for (int itemIndex = 0; itemIndex < items.Length; itemIndex++)
                {
                    var item = items[itemIndex];

                    // Decompress
                    int valueBitCount = (int)item.Count;
                    if (valueBitCount == 0)
                    {
                        continue;
                    }

                    int value = parser.ReadBits(valueBitCount);
                    int scale = 0;
                    for (int k = 0; k < valueBitCount; k++)
                    {
                        scale |= 0x1 << k;
                    }

                    float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale);
                    if (float.IsNaN(frameValue))
                    {
                        frameValue = 0;
                    }

                    values[itemIndex] = frameValue;
                }

                transforms.Add(values);
            }

            return(transforms);
        }
        /// <summary>
        /// decompresses transform values from a track
        /// </summary>
        /// <param name="parser"></param>
        /// <param name="dataOffset"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        private AnimTrackTransform[] DecompressTransform(SsbhParser parser, uint dataOffset, SsbhAnimCompressedHeader header)
        {
            AnimTrackTransform[] transforms = new AnimTrackTransform[header.FrameCount];

            // PreProcess
            SsbhAnimCompressedItem[] items = parser.ByteToType <SsbhAnimCompressedItem>(9);

            parser.Seek(dataOffset + header.DefaultDataOffset);

            float xsca = parser.ReadSingle();
            float ysca = parser.ReadSingle();
            float zsca = parser.ReadSingle();
            float xrot = parser.ReadSingle();
            float yrot = parser.ReadSingle();
            float zrot = parser.ReadSingle();
            float wrot = parser.ReadSingle();
            float xpos = parser.ReadSingle();
            float ypos = parser.ReadSingle();
            float zpos = parser.ReadSingle();
            float csca = parser.ReadSingle();

            parser.Seek(dataOffset + header.CompressedDataOffset);
            for (int frame = 0; frame < header.FrameCount; frame++)
            {
                AnimTrackTransform transform = new AnimTrackTransform()
                {
                    X  = xpos,
                    Y  = ypos,
                    Z  = zpos,
                    Rx = xrot,
                    Ry = yrot,
                    Rz = zrot,
                    Rw = wrot,
                    Sx = xsca,
                    Sy = ysca,
                    Sz = zsca,
                    CompensateScale = csca
                };
                for (int itemIndex = 0; itemIndex < items.Length; itemIndex++)
                {
                    // First check if this track should be parsed
                    // TODO: Don't hard code these flags.
                    if (!((itemIndex == 0 && (header.Flags & 0x3) == 0x3) || //isotropic scale
                          (itemIndex >= 0 && itemIndex <= 2 && (header.Flags & 0x3) == 0x1) ||       //normal scale
                          (itemIndex > 2 && itemIndex <= 5 && (header.Flags & 0x4) > 0) ||
                          (itemIndex > 5 && itemIndex <= 8 && (header.Flags & 0x8) > 0)))
                    {
                        continue;
                    }

                    var item = items[itemIndex];

                    // Decompress
                    int valueBitCount = (int)item.Count;
                    if (valueBitCount == 0)
                    {
                        continue;
                    }

                    int value = parser.ReadBits(valueBitCount);
                    int scale = 0;
                    for (int k = 0; k < valueBitCount; k++)
                    {
                        scale |= 0x1 << k;
                    }

                    float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale);
                    if (float.IsNaN(frameValue))
                    {
                        frameValue = 0;
                    }

                    // the Transform type relies a lot on flags

                    if ((header.Flags & 0x3) == 0x3)
                    {
                        //Scale Compensate
                        if (itemIndex == 0)
                        {
                            transform.CompensateScale = frameValue;
                        }
                    }
                    if ((header.Flags & 0x3) == 0x1)
                    {
                        //Scale normal
                        switch (itemIndex)
                        {
                        case 0:
                            transform.Sx = frameValue;
                            break;

                        case 1:
                            transform.Sy = frameValue;
                            break;

                        case 2:
                            transform.Sz = frameValue;
                            break;
                        }
                    }
                    //Rotation and Position
                    switch (itemIndex)
                    {
                    case 3:
                        transform.Rx = frameValue;
                        break;

                    case 4:
                        transform.Ry = frameValue;
                        break;

                    case 5:
                        transform.Rz = frameValue;
                        break;

                    case 6:
                        transform.X = frameValue;
                        break;

                    case 7:
                        transform.Y = frameValue;
                        break;

                    case 8:
                        transform.Z = frameValue;
                        break;
                    }
                }

                // Rotations have an extra bit at the end
                if ((header.Flags & 0x4) > 0)
                {
                    bool wFlip = parser.ReadBits(1) == 1;

                    // W is calculated
                    transform.Rw = (float)Math.Sqrt(Math.Abs(1 - (transform.Rx * transform.Rx + transform.Ry * transform.Ry + transform.Rz * transform.Rz)));

                    if (wFlip)
                    {
                        transform.Rw = -transform.Rw;
                    }
                }

                transforms[frame] = transform;
            }

            return(transforms);
        }
        private static void ReadBooleans(SsbhParser reader, List <object> output, uint dataOffset, SsbhAnimCompressedHeader header)
        {
            reader.Seek((int)dataOffset + header.CompressedDataOffset);
            // note: there is a section for "default" and "compressed items" but they seem to always be 0-ed out

            for (int i = 0; i < header.FrameCount; i++)
            {
                output.Add(reader.ReadBits(header.BitsPerEntry) == 1);
            }
        }
        private void ReadVector4(SsbhParser reader, List <object> output, uint dataOffset, SsbhAnimCompressedHeader header)
        {
            var decompressed = DecompressValues(reader, dataOffset, header, 4);

            foreach (var decom in decompressed)
            {
                output.Add(new AnimTrackCustomVector4(decom[0], decom[1], decom[2], decom[3]));
            }
        }
        private void ReadTransform(SsbhParser reader, List <object> output, uint dataOffset, SsbhAnimCompressedHeader header)
        {
            var decompressed = DecompressTransform(reader, dataOffset, header);

            foreach (var v in decompressed)
            {
                output.Add(v);
            }
        }