public override NewBlendableTransform GetBlendableTransformOnCurrentFrame(int hkxBoneIndex)
        {
            var track = HkxBoneIndexToTransformTrackMap[hkxBoneIndex];

            if (track == -1)
            {
                var skeleTransform = Skeleton.OriginalHavokSkeleton.Transforms[hkxBoneIndex];

                NewBlendableTransform defaultBoneTransformation = new NewBlendableTransform();

                defaultBoneTransformation.Scale.X = skeleTransform.Scale.Vector.X;
                defaultBoneTransformation.Scale.Y = skeleTransform.Scale.Vector.Y;
                defaultBoneTransformation.Scale.Z = skeleTransform.Scale.Vector.Z;

                defaultBoneTransformation.Rotation = new Quaternion(
                    skeleTransform.Rotation.Vector.X,
                    skeleTransform.Rotation.Vector.Y,
                    skeleTransform.Rotation.Vector.Z,
                    skeleTransform.Rotation.Vector.W);

                defaultBoneTransformation.Translation.X = skeleTransform.Position.Vector.X;
                defaultBoneTransformation.Translation.Y = skeleTransform.Position.Vector.Y;
                defaultBoneTransformation.Translation.Z = skeleTransform.Position.Vector.Z;

                return(defaultBoneTransformation);
            }

            float frame = (CurrentFrame % FrameCount) % NumFramesPerBlock;

            if (frame >= FrameCount - 1)
            {
                NewBlendableTransform currentFrame = GetTransformOnSpecificBlockAndFrame(track,
                                                                                         block: CurrentBlock, frame: (float)Math.Floor(frame));
                NewBlendableTransform nextFrame = GetTransformOnSpecificBlockAndFrame(track, block: 0, frame: 0);
                currentFrame = NewBlendableTransform.Lerp(frame % 1, currentFrame, nextFrame);
                return(currentFrame);
            }
            // Regular frame
            else
            {
                NewBlendableTransform currentFrame = GetTransformOnSpecificBlockAndFrame(track,
                                                                                         block: CurrentBlock, frame);
                return(currentFrame);
            }
        }
        public static NewBlendableTransform Lerp(float lerp, NewBlendableTransform a, NewBlendableTransform b)
        {
            float posX = Utils.Lerp(a.Translation.X, b.Translation.X, lerp);
            float posY = Utils.Lerp(a.Translation.Y, b.Translation.Y, lerp);
            float posZ = Utils.Lerp(a.Translation.Z, b.Translation.Z, lerp);

            float scaleX = Utils.Lerp(a.Scale.X, b.Scale.X, lerp);
            float scaleY = Utils.Lerp(a.Scale.Y, b.Scale.Y, lerp);
            float scaleZ = Utils.Lerp(a.Scale.Z, b.Scale.Z, lerp);

            float rotationX = Utils.Lerp(a.Rotation.X, b.Rotation.X, lerp);
            float rotationY = Utils.Lerp(a.Rotation.Y, b.Rotation.Y, lerp);
            float rotationZ = Utils.Lerp(a.Rotation.Z, b.Rotation.Z, lerp);
            float rotationW = Utils.Lerp(a.Rotation.W, b.Rotation.W, lerp);

            return(new NewBlendableTransform()
            {
                Translation = new Vector3(posX, posY, posZ),
                Scale = new Vector3(scaleX, scaleY, scaleZ),
                Rotation = new Quaternion(rotationX, rotationY, rotationZ, rotationW),
            });
        }
        private NewBlendableTransform GetTransformOnSpecificBlockAndFrame(int transformIndex, int block, float frame)
        {
            frame = (frame % FrameCount) % NumFramesPerBlock;

            NewBlendableTransform result = NewBlendableTransform.Identity;
            var track          = Tracks[block][transformIndex];
            var skeleTransform = Skeleton.OriginalHavokSkeleton.Transforms[TransformTrackIndexToHkxBoneMap[transformIndex]];

            //result.Scale.X = track.SplineScale?.ChannelX == null
            //    ? (IsAdditiveBlend ? 1 : track.StaticScale.X) : track.SplineScale.GetValueX(frame);
            //result.Scale.Y = track.SplineScale?.ChannelY == null
            //    ? (IsAdditiveBlend ? 1 : track.StaticScale.Y) : track.SplineScale.GetValueY(frame);
            //result.Scale.Z = track.SplineScale?.ChannelZ == null
            //    ? (IsAdditiveBlend ? 1 : track.StaticScale.Z) : track.SplineScale.GetValueZ(frame);

            if (track.SplineScale != null)
            {
                result.Scale.X = track.SplineScale.GetValueX(frame)
                                 ?? (IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.X);

                result.Scale.Y = track.SplineScale.GetValueY(frame)
                                 ?? (IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.Y);

                result.Scale.Z = track.SplineScale.GetValueZ(frame)
                                 ?? (IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.Z);
            }
            else
            {
                if (track.Mask.ScaleTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticX))
                {
                    result.Scale.X = track.StaticScale.X;
                }
                else
                {
                    result.Scale.X = IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.X;
                }

                if (track.Mask.ScaleTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticY))
                {
                    result.Scale.Y = track.StaticScale.Y;
                }
                else
                {
                    result.Scale.Y = IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.Y;
                }

                if (track.Mask.ScaleTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticZ))
                {
                    result.Scale.Z = track.StaticScale.Z;
                }
                else
                {
                    result.Scale.Z = IsAdditiveBlend ? 1 : skeleTransform.Scale.Vector.Z;
                }
            }

            if (IsAdditiveBlend)
            {
                result.Scale.X *= skeleTransform.Scale.Vector.X;
                result.Scale.Y *= skeleTransform.Scale.Vector.Y;
                result.Scale.Z *= skeleTransform.Scale.Vector.Z;
            }

            //if (result.Scale.LengthSquared() > (Vector3.One * 1.1f).LengthSquared())
            //{
            //    Console.WriteLine(":fatoof:");
            //}

            if (track.SplineRotation != null)//track.HasSplineRotation)
            {
                result.Rotation = track.SplineRotation.GetValue(frame);
            }
            else if (track.HasStaticRotation)
            {
                // We actually need static rotation or Gael hands become unbent among others
                result.Rotation = track.StaticRotation;
            }
            else
            {
                //result.Rotation = IsAdditiveBlend ? Quaternion.Identity : new Quaternion(
                //    skeleTransform.Rotation.Vector.X,
                //    skeleTransform.Rotation.Vector.Y,
                //    skeleTransform.Rotation.Vector.Z,
                //    skeleTransform.Rotation.Vector.W);
            }

            if (IsAdditiveBlend)
            {
                result.Rotation = new Quaternion(
                    skeleTransform.Rotation.Vector.X,
                    skeleTransform.Rotation.Vector.Y,
                    skeleTransform.Rotation.Vector.Z,
                    skeleTransform.Rotation.Vector.W) * result.Rotation;
            }

            if (track.SplinePosition != null)
            {
                result.Translation.X = track.SplinePosition.GetValueX(frame)
                                       ?? (IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.X);

                result.Translation.Y = track.SplinePosition.GetValueY(frame)
                                       ?? (IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.Y);

                result.Translation.Z = track.SplinePosition.GetValueZ(frame)
                                       ?? (IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.Z);
            }
            else
            {
                if (track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticX))
                {
                    result.Translation.X = track.StaticPosition.X;
                }
                else
                {
                    result.Translation.X = IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.X;
                }

                if (track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticY))
                {
                    result.Translation.Y = track.StaticPosition.Y;
                }
                else
                {
                    result.Translation.Y = IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.Y;
                }

                if (track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticZ))
                {
                    result.Translation.Z = track.StaticPosition.Z;
                }
                else
                {
                    result.Translation.Z = IsAdditiveBlend ? 0 : skeleTransform.Position.Vector.Z;
                }
            }

            //result.Translation.X = track.SplinePosition?.GetValueX(frame) ?? (IsAdditiveBlend ? 0 : track.StaticPosition.X);
            //result.Translation.Y = track.SplinePosition?.GetValueY(frame) ?? (IsAdditiveBlend ? 0 : track.StaticPosition.Y);
            //result.Translation.Z = track.SplinePosition?.GetValueZ(frame) ?? (IsAdditiveBlend ? 0 : track.StaticPosition.Z);

            //if (!IsAdditiveBlend && (!track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.SplineX) &&
            //    !track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticX)))
            //{
            //    result.Translation.X = skeleTransform.Position.Vector.X;
            //}

            //if (!IsAdditiveBlend && (!track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.SplineY) &&
            //    !track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticY)))
            //{
            //    result.Translation.Y = skeleTransform.Position.Vector.Y;
            //}

            //if (!IsAdditiveBlend && (!track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.SplineZ) &&
            //    !track.Mask.PositionTypes.Contains(Havok.SplineCompressedAnimation.FlagOffset.StaticZ)))
            //{
            //    result.Translation.Z = skeleTransform.Position.Vector.Z;
            //}

            if (IsAdditiveBlend)
            {
                result.Translation.X += skeleTransform.Position.Vector.X;
                result.Translation.Y += skeleTransform.Position.Vector.Y;
                result.Translation.Z += skeleTransform.Position.Vector.Z;
            }

            return(result);
        }