// Writing compressed & decompressing keyframes
        private RwCompressedKeyFrameData ReadCompressedKeyFrames(BinaryReader reader)
        {
            var compressedKeyFrames = new List <RwCompressedKeyFrame>();

            for (int i = 0; i < KeyFrames.Capacity; i++)
            {
                var compressedKeyFrame = new RwCompressedKeyFrame
                {
                    Time                = reader.ReadSingle(),
                    RotationX           = reader.ReadUInt16(),
                    RotationY           = reader.ReadUInt16(),
                    RotationZ           = reader.ReadUInt16(),
                    RotationW           = reader.ReadUInt16(),
                    TranslationX        = reader.ReadUInt16(),
                    TranslationY        = reader.ReadUInt16(),
                    TranslationZ        = reader.ReadUInt16(),
                    PreviousFrameOffset = reader.ReadInt32()
                };

                compressedKeyFrames.Add(compressedKeyFrame);
            }

            var customData = new RwCompressedKeyFrameCustomData
            {
                Offset = reader.ReadVector3(),
                Scalar = reader.ReadVector3()
            };

            return(new RwCompressedKeyFrameData(compressedKeyFrames, customData));
        }
        // Compress keyframes
        private void CompressKeyFrames(out List <RwCompressedKeyFrame> compressedKeyFrames, out RwCompressedKeyFrameCustomData customData)
        {
            var keyFrameToOffsetMap = new Dictionary <RwKeyFrame, int>();

            // Move translations >= 0
            customData = new RwCompressedKeyFrameCustomData
            {
                Offset = new Vector3
                         (
                    KeyFrames.Min(x => x.Translation.X),
                    KeyFrames.Min(x => x.Translation.Y),
                    KeyFrames.Min(x => x.Translation.Z)
                         )
            };

            compressedKeyFrames = new List <RwCompressedKeyFrame>();
            var offsetTranslations = new List <Vector3>();

            for (var i = 0; i < KeyFrames.Count; i++)
            {
                var keyFrame = KeyFrames[i];

                // add key frame to offset map for mapping the previous keyframe
                keyFrameToOffsetMap[keyFrame] = i * COMPRESSED_KEYFRAME_SIZE;

                // create the compressed key frame
                var compressedKeyFrame = new RwCompressedKeyFrame
                {
                    // time will remain the same
                    Time = keyFrame.Time,

                    // compress rotation quaternion
                    RotationX = CompressFloat(keyFrame.Rotation.X),
                    RotationY = CompressFloat(keyFrame.Rotation.Y),
                    RotationZ = CompressFloat(keyFrame.Rotation.Z),
                    RotationW = CompressFloat(keyFrame.Rotation.W),
                };

                // set to previous frame offset using the map
                if (keyFrame.Previous != null)
                {
                    compressedKeyFrame.PreviousFrameOffset = keyFrameToOffsetMap[keyFrame.Previous];
                }
                else
                {
                    compressedKeyFrame.PreviousFrameOffset = -1;
                }

                // add the newly created compressed key frame to the list
                // it's not yet fully initialized as the translations still
                // have to be processed
                compressedKeyFrames.Add(compressedKeyFrame);

                // offset the translation by the distance overall closest to zero
                var translation = keyFrame.Translation;
                translation.X -= customData.Offset.X;
                translation.Y -= customData.Offset.Y;
                translation.Z -= customData.Offset.Z;

                // add the offset translation to a seperate list
                offsetTranslations.Add(translation);
            }

            // calculate the translation scalar by taking the largest value of each
            // axis
            customData.Scalar = new Vector3(
                offsetTranslations.Max(x => x.X),
                offsetTranslations.Max(x => x.Y),
                offsetTranslations.Max(x => x.Z));

            // compress the translation using the offset translation and calculated scalar
            for (int i = 0; i < offsetTranslations.Count; i++)
            {
                compressedKeyFrames[i].TranslationX = CompressFloat(offsetTranslations[i].X / customData.Scalar.X);
                compressedKeyFrames[i].TranslationY = CompressFloat(offsetTranslations[i].Y / customData.Scalar.Y);
                compressedKeyFrames[i].TranslationZ = CompressFloat(offsetTranslations[i].Z / customData.Scalar.Z);
            }
        }