private static void ReadPerTrackData(FArchive reader, UAnimSequence animSequence, CAnimTrack track, int trackIndex) { var compressedData = (FUECompressedAnimData)animSequence.CompressedDataStructure; // this format uses different key storage Trace.Assert(compressedData.TranslationCompressionFormat == ACF_Identity); Trace.Assert(compressedData.RotationCompressionFormat == ACF_Identity); var transOffset = compressedData.CompressedTrackOffsets[trackIndex * 2]; var rotOffset = compressedData.CompressedTrackOffsets[trackIndex * 2 + 1]; var scaleOffset = compressedData.CompressedScaleOffsets.IsValid() ? compressedData.CompressedScaleOffsets.OffsetData[trackIndex] : -1; // read translation keys if (transOffset == -1) { track.KeyPos = new[] { FVector.ZeroVector }; } else { reader.Position = transOffset; ReadPerTrackVectorData(reader, "translation", ref track.KeyPos, ref track.KeyPosTime, animSequence.NumFrames); } // read rotation keys if (rotOffset == -1) { track.KeyQuat = new[] { FQuat.Identity }; } else { reader.Position = rotOffset; ReadPerTrackQuatData(reader, "rotation", ref track.KeyQuat, ref track.KeyQuatTime, animSequence.NumFrames); } // read scale keys if (scaleOffset != -1) { reader.Position = scaleOffset; ReadPerTrackVectorData(reader, "scale", ref track.KeyScale, ref track.KeyScaleTime, animSequence.NumFrames); } }
public AnimExporter(UAnimSequence animSequence) : this(animSequence.Skeleton.Load <USkeleton>() !, animSequence)
public abstract FFloatCurve[] ConvertCurves(UAnimSequence animSeq);
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); } }
public CAnimSequence(UAnimSequence originalSequence) { OriginalSequence = originalSequence; }