static AnimationHeader GetAnimationHeader(ByteChunk chunk)
        {
            if (chunk.BytesLeft == 0)
            {
                throw new Exception("Trying to load animation header with no data, chunk size = 0");
            }

            var header = new AnimationHeader();

            header.AnimationType      = chunk.ReadUInt32();
            header.Unknown0_alwaysOne = chunk.ReadUInt32();        // Always 1?
            header.FrameRate          = chunk.ReadSingle();
            var nameLength = chunk.ReadShort();

            header.SkeletonName        = chunk.ReadFixedLength(nameLength);
            header.Unknown1_alwaysZero = chunk.ReadUInt32();        // Always 0? padding?

            if (header.AnimationType == 7)
            {
                header.AnimationTotalPlayTimeInSec = chunk.ReadSingle(); // Play time
            }
            bool isSupportedAnimationFile = header.AnimationType == 5 || header.AnimationType == 6 || header.AnimationType == 7;

            if (!isSupportedAnimationFile)
            {
                throw new Exception($"Unsuported animation format: {header.AnimationType}");
            }

            return(header);
        }
        static Frame ReadFrame(ByteChunk chunk, uint positions, uint rotations)
        {
            var frame = new Frame();

            for (int j = 0; j < positions; j++)
            {
                var vector = new RmvVector3(chunk.ReadSingle(), chunk.ReadSingle(), chunk.ReadSingle());
                frame.Transforms.Add(vector);
            }

            for (int j = 0; j < rotations; j++)
            {
                var maxValue = 1.0f / (float)short.MaxValue;
                var quat     = new short[4] {
                    chunk.ReadShort(), chunk.ReadShort(), chunk.ReadShort(), chunk.ReadShort()
                };

                var quaternion = new RmvVector4(quat[0] * maxValue, quat[1] * maxValue, quat[2] * maxValue, quat[3] * maxValue);
                frame.Quaternion.Add(quaternion);
            }
            return(frame);
        }
        public AnimationBinEntry(ByteChunk data)
        {
            Name         = data.ReadString();
            SkeletonName = data.ReadString();
            MountName    = data.ReadString();
            var count = data.ReadInt32();

            for (int i = 0; i < count; i++)
            {
                FragmentReferences.Add(new FragmentReference(data));
            }
            Unknown = data.ReadShort();
        }
        public static AnimationFile Create(ByteChunk chunk)
        {
            if (chunk.BytesLeft == 0)
            {
                throw new Exception("Trying to load animation with no data, chunk size = 0");
            }
            var output = new AnimationFile();

            chunk.Reset();
            output.Header = GetAnimationHeader(chunk);

            var boneCount = chunk.ReadUInt32();

            output.Bones = new BoneInfo[boneCount];
            for (int i = 0; i < boneCount; i++)
            {
                var boneNameSize = chunk.ReadShort();
                output.Bones[i] = new BoneInfo()
                {
                    Name     = chunk.ReadFixedLength(boneNameSize),
                    ParentId = chunk.ReadInt32(),
                    Id       = i
                };
            }

            // Remapping tables, not sure how they really should be used, but this works.
            for (int i = 0; i < boneCount; i++)
            {
                int mappingValue = chunk.ReadInt32();
                output.TranslationMappings.Add(new AnimationBoneMapping(mappingValue));
            }

            for (int i = 0; i < boneCount; i++)
            {
                int mappingValue = chunk.ReadInt32();
                output.RotationMappings.Add(new AnimationBoneMapping(mappingValue));
            }

            // A single static frame - Can be inverse, a pose or empty. Not sure? Hand animations are stored here
            if (output.Header.AnimationType == 7)
            {
                var staticPosCount = chunk.ReadUInt32();
                var staticRotCount = chunk.ReadUInt32();
                if (staticPosCount != 0 || staticRotCount != 0)
                {
                    output.StaticFrame = ReadFrame(chunk, staticPosCount, staticRotCount);
                }
            }

            // Animation Data
            var animPosCount = chunk.ReadInt32();
            var animRotCount = chunk.ReadInt32();
            var frameCount   = chunk.ReadInt32();  // Always 3 when there is no data? Why?

            if (animPosCount != 0 || animRotCount != 0)
            {
                for (int i = 0; i < frameCount; i++)
                {
                    var frame = ReadFrame(chunk, (uint)animPosCount, (uint)animRotCount);
                    output.DynamicFrames.Add(frame);
                }
            }
            // ----------------------

            return(output);
        }