private static void ReadPerTrackQuatData(FArchive Ar, string trackKind, ref FQuat[] dstKeys, ref float[] dstTimeKeys, int numFrames) { var packedInfo = Ar.Read <uint>(); var keyFormat = (AnimationCompressionFormat)(packedInfo >> 28); var componentMask = (int)((packedInfo >> 24) & 0xF); var numKeys = (int)(packedInfo & 0xFFFFFF); var hasTimeTracks = (componentMask & 8) != 0; var mins = FVector.ZeroVector; var ranges = FVector.ZeroVector; dstKeys = new FQuat[numKeys]; if (keyFormat == ACF_IntervalFixed32NoW) { // read mins/maxs if ((componentMask & 1) != 0) { mins.X = Ar.Read <float>(); ranges.X = Ar.Read <float>(); } if ((componentMask & 2) != 0) { mins.Y = Ar.Read <float>(); ranges.Y = Ar.Read <float>(); } if ((componentMask & 4) != 0) { mins.Z = Ar.Read <float>(); ranges.Z = Ar.Read <float>(); } } for (var keyIndex = 0; keyIndex < numKeys; keyIndex++) { dstKeys[keyIndex] = keyFormat switch { ACF_None or ACF_Float96NoW => Ar.ReadQuatFloat96NoW(), ACF_Fixed48NoW => Ar.ReadQuatFixed48NoW(componentMask), ACF_Fixed32NoW => Ar.ReadQuatFixed32NoW(), ACF_IntervalFixed32NoW => Ar.ReadQuatIntervalFixed32NoW(mins, ranges), ACF_Float32NoW => Ar.ReadQuatFloat32NoW(), ACF_Identity => FQuat.Identity, _ => throw new ParserException(Ar, $"Unknown {trackKind} compression method: {(int) keyFormat} ({keyFormat})") }; } // align to 4 bytes Ar.Position = Ar.Position.Align(4); if (hasTimeTracks) { ReadTimeArray(Ar, numKeys, out dstTimeKeys, numFrames); } }
private static void ReadKeyLerpData(FArchive reader, UAnimSequence animSequence, CAnimTrack track, int trackIndex, bool hasTimeTracks) { var compressedData = (FUECompressedAnimData)animSequence.CompressedDataStructure; var transOffset = compressedData.CompressedTrackOffsets[trackIndex * 4]; var transKeys = compressedData.CompressedTrackOffsets[trackIndex * 4 + 1]; var rotOffset = compressedData.CompressedTrackOffsets[trackIndex * 4 + 2]; var rotKeys = compressedData.CompressedTrackOffsets[trackIndex * 4 + 3]; track.KeyPos = new FVector[transKeys]; track.KeyQuat = new FQuat[rotKeys]; var mins = FVector.ZeroVector; var ranges = FVector.ZeroVector; // read translation keys if (transKeys > 0) { reader.Position = transOffset; var translationCompressionFormat = compressedData.TranslationCompressionFormat; if (transKeys == 1) { translationCompressionFormat = ACF_None; // single key is stored without compression } // read mins/ranges if (translationCompressionFormat == ACF_IntervalFixed32NoW) { mins = reader.Read <FVector>(); ranges = reader.Read <FVector>(); } for (var keyIndex = 0; keyIndex < transKeys; keyIndex++) { track.KeyPos[keyIndex] = translationCompressionFormat switch { ACF_None => reader.Read <FVector>(), ACF_Float96NoW => reader.Read <FVector>(), ACF_IntervalFixed32NoW => reader.ReadVectorIntervalFixed32(mins, ranges), ACF_Fixed48NoW => reader.ReadVectorFixed48(), ACF_Identity => FVector.ZeroVector, _ => throw new ParserException($"Unknown translation compression method: {(int) translationCompressionFormat} ({translationCompressionFormat})") }; } // align to 4 bytes reader.Position = reader.Position.Align(4); if (hasTimeTracks) { ReadTimeArray(reader, transKeys, out track.KeyPosTime, animSequence.NumFrames); } } else { // A.KeyPos.Add(FVector.ZeroVector); // appNotify("No translation keys!"); } // read rotation keys reader.Position = rotOffset; var rotationCompressionFormat = compressedData.RotationCompressionFormat; if (rotKeys == 1) { rotationCompressionFormat = ACF_Float96NoW; // single key is stored without compression } else if (rotKeys > 1 && rotationCompressionFormat == ACF_IntervalFixed32NoW) { // Mins/Ranges are read only when needed - i.e. for ACF_IntervalFixed32NoW mins = reader.Read <FVector>(); ranges = reader.Read <FVector>(); } for (var k = 0; k < rotKeys; k++) { track.KeyQuat[k] = rotationCompressionFormat switch { ACF_None => reader.Read <FQuat>(), ACF_Float96NoW => reader.ReadQuatFloat96NoW(), ACF_Fixed48NoW => reader.ReadQuatFixed48NoW(), ACF_Fixed32NoW => reader.ReadQuatFixed32NoW(), ACF_IntervalFixed32NoW => reader.ReadQuatIntervalFixed32NoW(mins, ranges), ACF_Float32NoW => reader.ReadQuatFloat32NoW(), ACF_Identity => FQuat.Identity, _ => throw new ParserException($"Unknown rotation compression method: {(int) rotationCompressionFormat} ({rotationCompressionFormat})") }; } if (hasTimeTracks) { // align to 4 bytes reader.Position = reader.Position.Align(4); ReadTimeArray(reader, rotKeys, out track.KeyQuatTime, animSequence.NumFrames); } }