UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
AnimationCompression.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 AnimationCompression.h: Skeletal mesh animation compression.
5=============================================================================*/
6
7#pragma once
8
9#include "CoreMinimal.h"
10#include "Math/FloatPacker.h"
11#include "Animation/AnimEnums.h"
12#include "EngineLogs.h"
13
15
16// Thresholds
17#define TRANSLATION_ZEROING_THRESHOLD (0.0001f)
18#define QUATERNION_ZEROING_THRESHOLD (0.0003f)
19#define SCALE_ZEROING_THRESHOLD (0.000001f)
20
22#define END_EFFECTOR_DUMMY_BONE_LENGTH_SOCKET (50.f)
24#define END_EFFECTOR_DUMMY_BONE_LENGTH (5.f)
25
26#define Quant16BitDiv (32767.f)
27#define Quant16BitFactor (32767.f)
28#define Quant16BitOffs (32767)
29
30#define Quant10BitDiv (511.f)
31#define Quant10BitFactor (511.f)
32#define Quant10BitOffs (511)
33
34#define Quant11BitDiv (1023.f)
35#define Quant11BitFactor (1023.f)
36#define Quant11BitOffs (1023)
37
39{
40 //@TODO: Explore different scales
41 inline static constexpr int32 LogScale = 7;
42
43 template<typename ValueType>
44 inline ValueType UnalignedRead(const void* Ptr)
45 {
46#if PLATFORM_SUPPORTS_UNALIGNED_LOADS
47 return *reinterpret_cast<const ValueType*>(Ptr);
48#else
49 // TODO: On ARM devices this will be slower than it needs to be.
50 // To make it fast, __packed keyword must be used with the reinterpret cast.
51 // Ideally this code would be moved into FPlatformMisc to handle this per platform properly.
52 ValueType Result;
53 memcpy(&Result, Ptr, sizeof(ValueType));
54 return Result;
55#endif
56 }
57
62 template <typename T>
63 inline T Interpolate(const T& A, const T& B, float Alpha)
64 {
65 // only the custom instantiations below are valid
66 check(0);
67 return 0;
68 }
69
71 template <> inline FVector3f Interpolate<FVector3f>(const FVector3f& A, const FVector3f& B, float Alpha)
72 {
73 return FMath::Lerp(A, B, Alpha);
74 }
75 template <> inline FVector3d Interpolate<FVector3d>(const FVector3d& A, const FVector3d& B, float Alpha) // LWC_TODO: double Alpha?
76 {
77 return FMath::Lerp(A, B, Alpha);
78 }
79
81 template <> inline FQuat4d Interpolate<FQuat4d>(const FQuat4d& A, const FQuat4d& B, float Alpha)
82 {
83 FQuat4d result = FQuat4d::FastLerp(A, B, Alpha);
84 result.Normalize();
85
86 return result;
87 }
88 template <> inline FQuat4f Interpolate<FQuat4f>(const FQuat4f& A, const FQuat4f& B, float Alpha)
89 {
90 FQuat4f result = FQuat4f::FastLerp(A, B, Alpha);
91 result.Normalize();
92 return result;
93 }
94}
95
97{
98public:
102
105
106 explicit FQuatFixed48NoW(const FQuat4f& Quat)
107 {
108 FromQuat( Quat );
109 }
110
111 void FromQuat(const FQuat4f& Quat)
112 {
113 FQuat4f Temp( Quat );
114 if ( Temp.W < 0.f )
115 {
116 Temp.X = -Temp.X;
117 Temp.Y = -Temp.Y;
118 Temp.Z = -Temp.Z;
119 Temp.W = -Temp.W;
120 }
121 Temp.Normalize();
122
126 }
127
128 void ToQuat(FQuat4f& Out) const
129 {
130 const float FX = ((int32)X - (int32)Quant16BitOffs) / Quant16BitDiv;
131 const float FY = ((int32)Y - (int32)Quant16BitOffs) / Quant16BitDiv;
132 const float FZ = ((int32)Z - (int32)Quant16BitOffs) / Quant16BitDiv;
133 const float WSquared = 1.f - FX*FX - FY*FY - FZ*FZ;
134
135 Out.X = FX;
136 Out.Y = FY;
137 Out.Z = FZ;
138 Out.W = WSquared > 0.f ? FMath::Sqrt( WSquared ) : 0.f;
139 }
140
142 {
143 Ar << Quat.X;
144 Ar << Quat.Y;
145 Ar << Quat.Z;
146 return Ar;
147 }
148};
149
151{
152public:
154
157
158 explicit FQuatFixed32NoW(const FQuat4f& Quat)
159 {
160 FromQuat( Quat );
161 }
162
163 void FromQuat(const FQuat4f& Quat)
164 {
165 FQuat4f Temp( Quat );
166 if ( Temp.W < 0.f )
167 {
168 Temp.X = -Temp.X;
169 Temp.Y = -Temp.Y;
170 Temp.Z = -Temp.Z;
171 Temp.W = -Temp.W;
172 }
173 Temp.Normalize();
174
178
179 // 21-31 X, 10-20 Y, 0-9 Z.
180 const uint32 XShift = 21;
181 const uint32 YShift = 10;
182 Packed = (PackedX << XShift) | (PackedY << YShift) | (PackedZ);
183 }
184
185 template<bool bIsDataAligned>
186 static FQuat4f ToQuat(const uint32* PackedValue)
187 {
188 const uint32 XShift = 21;
189 const uint32 YShift = 10;
190 const uint32 ZMask = 0x000003ff;
191 const uint32 YMask = 0x001ffc00;
192 const uint32 XMask = 0xffe00000;
193
194 const uint32 Packed = bIsDataAligned ? *PackedValue : AnimationCompressionUtils::UnalignedRead<uint32>(PackedValue);
195 const uint32 UnpackedX = Packed >> XShift;
196 const uint32 UnpackedY = (Packed & YMask) >> YShift;
197 const uint32 UnpackedZ = (Packed & ZMask);
198
199 const float X = ((int32)UnpackedX - (int32)Quant11BitOffs) / Quant11BitDiv;
200 const float Y = ((int32)UnpackedY - (int32)Quant11BitOffs) / Quant11BitDiv;
201 const float Z = ((int32)UnpackedZ - (int32)Quant10BitOffs) / Quant10BitDiv;
202 const float WSquared = 1.f - X*X - Y*Y - Z*Z;
203
204 return FQuat4f(X, Y, Z, WSquared > 0.f ? FMath::Sqrt(WSquared) : 0.f);
205 }
206
207 void ToQuat(FQuat4f& Out) const
208 {
209 Out = ToQuat<true>(&Packed);
210 }
211
213 {
214 Ar << Quat.Packed;
215 return Ar;
216 }
217};
218
220{
221public:
222 union
223 {
224 struct
225 {
226 float X;
227 float Y;
228 float Z;
229 };
230
231 UE_DEPRECATED(all, "For internal use only")
233 };
234
237
238 explicit FQuatFloat96NoW(const FQuat4f& Quat)
239 {
240 FromQuat( Quat );
241 }
242
243 FQuatFloat96NoW(float InX, float InY, float InZ)
244 : X( InX )
245 , Y( InY )
246 , Z( InZ )
247 {}
248
249 void FromQuat(const FQuat4f& Quat)
250 {
251 FQuat4f Temp( Quat );
252 if ( Temp.W < 0.f )
253 {
254 Temp.X = -Temp.X;
255 Temp.Y = -Temp.Y;
256 Temp.Z = -Temp.Z;
257 Temp.W = -Temp.W;
258 }
259 Temp.Normalize();
260 X = UE_REAL_TO_FLOAT(Temp.X);
261 Y = UE_REAL_TO_FLOAT(Temp.Y);
262 Z = UE_REAL_TO_FLOAT(Temp.Z);
263 }
264
265 template<bool bIsDataAligned = true>
266 static FQuat4f ToQuat(const float* Values)
267 {
268 const float X = bIsDataAligned ? *Values++ : AnimationCompressionUtils::UnalignedRead<float>(Values++);
269 const float Y = bIsDataAligned ? *Values++ : AnimationCompressionUtils::UnalignedRead<float>(Values++);
270 const float Z = bIsDataAligned ? *Values++ : AnimationCompressionUtils::UnalignedRead<float>(Values++);
271 const float WSquared = 1.f - X*X - Y*Y - Z*Z;
272
273 return FQuat4f(X, Y, Z, WSquared > 0.f ? FMath::Sqrt(WSquared) : 0.f);
274 }
275
282
284 {
285 Ar << Quat.X;
286 Ar << Quat.Y;
287 Ar << Quat.Z;
288 return Ar;
289 }
290};
291
292
293
295{
296public:
300
303
304 explicit FVectorFixed48(const FVector3f& Vec)
305 {
306 FromVector( Vec );
307 }
308
310 {
311 FVector3f Temp( Vec / 128.0f );
312
316 }
317
318 void ToVector(FVector3f& Out) const
319 {
320 const float FX = ((int32)X - (int32)Quant16BitOffs) / Quant16BitDiv;
321 const float FY = ((int32)Y - (int32)Quant16BitOffs) / Quant16BitDiv;
322 const float FZ = ((int32)Z - (int32)Quant16BitOffs) / Quant16BitDiv;
323
324 Out.X = FX * 128.0f;
325 Out.Y = FY * 128.0f;
326 Out.Z = FZ * 128.0f;
327 }
328
330 {
331 Ar << Vec.X;
332 Ar << Vec.Y;
333 Ar << Vec.Z;
334 return Ar;
335 }
336};
337
339{
340public:
342
345
346 explicit FVectorIntervalFixed32NoW(const FVector3f& Value, const float* Mins, const float *Ranges)
347 {
348 FromVector( Value, Mins, Ranges );
349 }
350
351 void FromVector(const FVector3f& Value, const float* Mins, const float *Ranges)
352 {
353 FVector3f Temp( Value );
354
355 Temp.X -= Mins[0];
356 Temp.Y -= Mins[1];
357 Temp.Z -= Mins[2];
358
359 const uint32 PackedX = (int32)((Temp.X / Ranges[0]) * Quant10BitFactor ) + Quant10BitOffs;
360 const uint32 PackedY = (int32)((Temp.Y / Ranges[1]) * Quant11BitFactor ) + Quant11BitOffs;
361 const uint32 PackedZ = (int32)((Temp.Z / Ranges[2]) * Quant11BitFactor ) + Quant11BitOffs;
362
363 // 21-31 Z, 10-20 Y, 0-9 X.
364 const uint32 ZShift = 21;
365 const uint32 YShift = 10;
366 Packed = (PackedZ << ZShift) | (PackedY << YShift) | (PackedX);
367 }
368
369 template<bool bIsDataAligned = true>
370 static FVector3f ToVector(const float* Mins, const float *Ranges, const uint32* PackedValue)
371 {
372 const uint32 ZShift = 21;
373 const uint32 YShift = 10;
374 const uint32 XMask = 0x000003ff;
375 const uint32 YMask = 0x001ffc00;
376 const uint32 ZMask = 0xffe00000;
377
378 const uint32 Packed = bIsDataAligned ? *PackedValue : AnimationCompressionUtils::UnalignedRead<uint32>(PackedValue);
379 const uint32 UnpackedZ = Packed >> ZShift;
380 const uint32 UnpackedY = (Packed & YMask) >> YShift;
381 const uint32 UnpackedX = (Packed & XMask);
382
383 const float X = ((((int32)UnpackedX - (int32)Quant10BitOffs) / Quant10BitDiv) * Ranges[0] + Mins[0]);
384 const float Y = ((((int32)UnpackedY - (int32)Quant11BitOffs) / Quant11BitDiv) * Ranges[1] + Mins[1]);
385 const float Z = ((((int32)UnpackedZ - (int32)Quant11BitOffs) / Quant11BitDiv) * Ranges[2] + Mins[2]);
386
387 return FVector3f(X, Y, Z);
388 }
389
390 void ToVector(FVector3f& Out, const float* Mins, const float *Ranges) const
391 {
392 Out = ToVector<true>(Mins, Ranges, &Packed);
393 }
394
396 {
397 Ar << Value.Packed;
398 return Ar;
399 }
400};
401
402
404{
405public:
407
410
411 explicit FQuatIntervalFixed32NoW(const FQuat4f& Quat, const float* Mins, const float *Ranges)
412 {
413 FromQuat( Quat, Mins, Ranges );
414 }
415
416 void FromQuat(const FQuat4f& Quat, const float* Mins, const float *Ranges)
417 {
418 FQuat4f Temp( Quat );
419 if ( Temp.W < 0.f )
420 {
421 Temp.X = -Temp.X;
422 Temp.Y = -Temp.Y;
423 Temp.Z = -Temp.Z;
424 Temp.W = -Temp.W;
425 }
426 Temp.Normalize();
427
428 Temp.X -= Mins[0];
429 Temp.Y -= Mins[1];
430 Temp.Z -= Mins[2];
431
432 const uint32 PackedX = (int32)((Temp.X / Ranges[0]) * Quant11BitFactor ) + Quant11BitOffs;
433 const uint32 PackedY = (int32)((Temp.Y / Ranges[1]) * Quant11BitFactor ) + Quant11BitOffs;
434 const uint32 PackedZ = (int32)((Temp.Z / Ranges[2]) * Quant10BitFactor ) + Quant10BitOffs;
435
436 // 21-31 X, 10-20 Y, 0-9 Z.
437 const uint32 XShift = 21;
438 const uint32 YShift = 10;
439 Packed = (PackedX << XShift) | (PackedY << YShift) | (PackedZ);
440 }
441
442 template<bool bIsDataAligned>
443 static FQuat4f ToQuat(const float* Mins, const float *Ranges, const uint32* PackedValue)
444 {
445 const uint32 XShift = 21;
446 const uint32 YShift = 10;
447 const uint32 ZMask = 0x000003ff;
448 const uint32 YMask = 0x001ffc00;
449 const uint32 XMask = 0xffe00000;
450
451 const uint32 Packed = bIsDataAligned ? *PackedValue : AnimationCompressionUtils::UnalignedRead<uint32>(PackedValue);
452 const uint32 UnpackedX = Packed >> XShift;
453 const uint32 UnpackedY = (Packed & YMask) >> YShift;
454 const uint32 UnpackedZ = (Packed & ZMask);
455
456 const float X = ((((int32)UnpackedX - (int32)Quant11BitOffs) / Quant11BitDiv) * Ranges[0] + Mins[0]);
457 const float Y = ((((int32)UnpackedY - (int32)Quant11BitOffs) / Quant11BitDiv) * Ranges[1] + Mins[1]);
458 const float Z = ((((int32)UnpackedZ - (int32)Quant10BitOffs) / Quant10BitDiv) * Ranges[2] + Mins[2]);
459 const float WSquared = 1.f - X*X - Y*Y - Z*Z;
460
461 return FQuat4f(X, Y, Z, WSquared > 0.f ? FMath::Sqrt(WSquared) : 0.f);
462 }
463
464 void ToQuat(FQuat4f& Out, const float* Mins, const float *Ranges) const
465 {
466 Out = ToQuat<true>(Mins, Ranges, &Packed);
467 }
468
470 {
471 Ar << Quat.Packed;
472 return Ar;
473 }
474};
475
477{
478public:
480
483
484 explicit FQuatFloat32NoW(const FQuat4f& Quat)
485 {
486 FromQuat( Quat );
487 }
488
489 void FromQuat(const FQuat4f& Quat)
490 {
491 FQuat4f Temp( Quat );
492 if ( Temp.W < 0.f )
493 {
494 Temp.X = -Temp.X;
495 Temp.Y = -Temp.Y;
496 Temp.Z = -Temp.Z;
497 Temp.W = -Temp.W;
498 }
499 Temp.Normalize();
500
503
504 const uint32 PackedX = Packer7e3.Encode( Temp.X );
505 const uint32 PackedY = Packer7e3.Encode( Temp.Y );
506 const uint32 PackedZ = Packer6e3.Encode( Temp.Z );
507
508 // 21-31 X, 10-20 Y, 0-9 Z.
509 const uint32 XShift = 21;
510 const uint32 YShift = 10;
511 Packed = (PackedX << XShift) | (PackedY << YShift) | (PackedZ);
512 }
513
514 template<bool bIsDataAligned>
515 static FQuat4f ToQuat(const uint32* PackedValue)
516 {
517 const uint32 XShift = 21;
518 const uint32 YShift = 10;
519 const uint32 ZMask = 0x000003ff;
520 const uint32 YMask = 0x001ffc00;
521 const uint32 XMask = 0xffe00000;
522
523 const uint32 Packed = bIsDataAligned ? *PackedValue : AnimationCompressionUtils::UnalignedRead<uint32>(PackedValue);
524 const uint32 UnpackedX = Packed >> XShift;
525 const uint32 UnpackedY = (Packed & YMask) >> YShift;
526 const uint32 UnpackedZ = (Packed & ZMask);
527
530
531 const float X = Packer7e3.Decode(UnpackedX);
532 const float Y = Packer7e3.Decode(UnpackedY);
533 const float Z = Packer6e3.Decode(UnpackedZ);
534 const float WSquared = 1.f - X*X - Y*Y - Z*Z;
535
536 return FQuat4f(X, Y, Z, WSquared > 0.f ? FMath::Sqrt(WSquared) : 0.f);
537 }
538
539 void ToQuat(FQuat4f& Out) const
540 {
541 Out = ToQuat<true>(&Packed);
542 }
543
545 {
546 Ar << Quat.Packed;
547 return Ar;
548 }
549};
550
552//
553// Handy Template Decompressors
554//
556
565template <int32 FORMAT, bool bIsDataAligned = true>
566inline void DecompressRotation(FQuat4f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
567{
568 // this if-else stack gets compiled away to a single result based on the template parameter
569 if ( FORMAT == ACF_None )
570 {
571 // due to alignment issue, this crahses accessing non aligned
572 // we don't think this is common case, so this is slower.
573 const float* Keys = (const float*)KeyData;
574 const float X = bIsDataAligned ? Keys[0] : AnimationCompressionUtils::UnalignedRead<float>(&Keys[0]);
575 const float Y = bIsDataAligned ? Keys[1] : AnimationCompressionUtils::UnalignedRead<float>(&Keys[1]);
576 const float Z = bIsDataAligned ? Keys[2] : AnimationCompressionUtils::UnalignedRead<float>(&Keys[2]);
577 const float W = bIsDataAligned ? Keys[3] : AnimationCompressionUtils::UnalignedRead<float>(&Keys[3]);
578 Out = FQuat4f(X, Y, Z, W);
579 }
580 else if ( FORMAT == ACF_Float96NoW )
581 {
582 Out = FQuatFloat96NoW::ToQuat<bIsDataAligned>((const float*)KeyData);
583 }
584 else if ( FORMAT == ACF_Fixed32NoW )
585 {
586 Out = FQuatFixed32NoW::ToQuat<bIsDataAligned>((const uint32*)KeyData);
587 }
588 else if ( FORMAT == ACF_Fixed48NoW )
589 {
590 ((FQuatFixed48NoW*)KeyData)->ToQuat( Out );
591 }
592 else if ( FORMAT == ACF_IntervalFixed32NoW )
593 {
594 const float* RESTRICT Mins = (float*)TopOfStream;
595 const float* RESTRICT Ranges = (float*)(TopOfStream+sizeof(float)*3);
596 Out = FQuatIntervalFixed32NoW::ToQuat<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
597 }
598 else if ( FORMAT == ACF_Float32NoW )
599 {
600 Out = FQuatFloat32NoW::ToQuat<bIsDataAligned>((const uint32*)KeyData);
601 }
602 else if ( FORMAT == ACF_Identity )
603 {
604 Out = FQuat4f::Identity;
605 }
606 else
607 {
608 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)FORMAT );
609 Out = FQuat4f::Identity;
610 }
611}
612
621template <int32 FORMAT, bool bIsDataAligned = true>
622inline void DecompressTranslation(FVector3f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
623{
624 if ( (FORMAT == ACF_None) || (FORMAT == ACF_Float96NoW) )
625 {
626 Out = bIsDataAligned ? *((FVector3f*)KeyData) : AnimationCompressionUtils::UnalignedRead<FVector3f>(KeyData);
627 }
628 else if ( FORMAT == ACF_IntervalFixed32NoW )
629 {
630 const float* RESTRICT Mins = (float*)TopOfStream;
631 const float* RESTRICT Ranges = (float*)(TopOfStream+sizeof(float)*3);
632 Out = FVectorIntervalFixed32NoW::ToVector<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
633 }
634 else if ( FORMAT == ACF_Identity )
635 {
637 }
638 else if ( FORMAT == ACF_Fixed48NoW )
639 {
640 ((FVectorFixed48*)KeyData)->ToVector( Out );
641 }
642 else
643 {
644 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)FORMAT );
645 // Silence compilers warning about a value potentially not being assigned.
647 }
648}
649
658template <int32 FORMAT, bool bIsDataAligned = true>
659inline void DecompressScale(FVector3f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
660{
661 if ( (FORMAT == ACF_None) || (FORMAT == ACF_Float96NoW) )
662 {
663 Out = bIsDataAligned ? *((FVector3f*)KeyData) : AnimationCompressionUtils::UnalignedRead<FVector3f>(KeyData);
664 }
665 else if ( FORMAT == ACF_IntervalFixed32NoW )
666 {
667 const float* RESTRICT Mins = (float*)TopOfStream;
668 const float* RESTRICT Ranges = (float*)(TopOfStream+sizeof(float)*3);
669 Out = FVectorIntervalFixed32NoW::ToVector<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
670 }
671 else if ( FORMAT == ACF_Identity )
672 {
674 }
675 else if ( FORMAT == ACF_Fixed48NoW )
676 {
677 ((FVectorFixed48*)KeyData)->ToVector( Out );
678 }
679 else
680 {
681 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)FORMAT );
682 // Silence compilers warning about a value potentially not being assigned.
684 }
685}
686
687
688
693{
694public:
695 // Log2MaxValue of 0 => -1..1
696 // Log2MaxValue of 7 => -128..128
697 // Can be 0..15
710 {
711 const int32 QuantOffset = (1 << (15 - Log2MaxValue)) - 1;
712 const float QuantFactor = (float)(QuantOffset >> Log2MaxValue);
713 return (uint16)((int32)(Value * QuantFactor) + QuantOffset);
714 }
715
724 template <int32 Log2MaxValue>
726 {
727 const int32 QuantOffset = (1 << (15 - Log2MaxValue)) - 1;
728 const float InvQuantFactor = 1.0f / (float)(QuantOffset >> Log2MaxValue);
729
731 }
732
740 static int32 MakeHeader(const int32 NumKeys, const int32 KeyFormat, const int32 KeyFlags, bool bReallyNeedsFrameTable)
741 {
742 return (NumKeys & 0x00FFFFFF) | ((KeyFormat & 0xF) << 28) | ((KeyFlags & 0x7) << 24) | ((bReallyNeedsFrameTable & 0x1) << 27);
743 }
744
752 {
753 return Header & 0x00FFFFFF;
754 }
755
762 static void GetAllSizesFromFormat(int32 KeyFormat, int32 FormatFlags,
765 {
768
769 // Note: this method can be used for translation too, but animation sequences compressed with this codec will
770 // use ACF_Float96NoW for uncompressed translation, so using the rotation table is still valid
772 FixedComponentSize = sizeof(float);
773
774 const int32 ComponentLookup = PerTrackNumComponentTable[(FormatFlags & 0x7) | (KeyFormat << 3)];
775
777 {
780 }
781 else
782 {
783 // Min/Range floats for all non-zero channels
786 }
787 }
788
801
809 static inline void DecomposeHeader(int32 Header, int32& KeyFormat, int32& NumKeys, int32& FormatFlags)
810 {
811 NumKeys = Header & 0x00FFFFFF;
812 FormatFlags = (Header >> 24) & 0x0F;
813 KeyFormat = (Header >> 28) & 0x0F;
814 }
815
827 static inline void DecomposeHeader(int32 Header, int32& KeyFormat, int32& NumKeys, int32& FormatFlags, int32& BytesPerKey, int32& FixedBytes)
828 {
829 NumKeys = Header & 0x00FFFFFF;
830 FormatFlags = (Header >> 24) & 0x0F;
831 KeyFormat = (Header >> 28) & 0x0F;
832
833 // Figure out the component sizes / counts (they can be changed per-format)
834 GetByteSizesFromFormat(KeyFormat, FormatFlags, /*OUT*/ BytesPerKey, /*OUT*/ FixedBytes);
835 }
836
838 template<bool bIsDataAligned = true>
839 static inline void DecompressTranslation(int32 Format, int32 FormatFlags, FVector3f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
840 {
841 if( Format == ACF_Float96NoW )
842 {
843 // Legacy Format, all components stored
844 if( (FormatFlags & 7) == 0 )
845 {
846 Out = bIsDataAligned ? *((FVector3f*)KeyData) : AnimationCompressionUtils::UnalignedRead<FVector3f>(KeyData);
847 }
848 // Stored per components
849 else
850 {
851 const float* RESTRICT TypedKeyData = (const float*)KeyData;
852 if (FormatFlags & 1)
853 {
854 Out.X = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
855 }
856 else
857 {
858 Out.X = 0.0f;
859 }
860
861 if (FormatFlags & 2)
862 {
863 Out.Y = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
864 }
865 else
866 {
867 Out.Y = 0.0f;
868 }
869
870 if (FormatFlags & 4)
871 {
872 Out.Z = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
873 }
874 else
875 {
876 Out.Z = 0.0f;
877 }
878 }
879 }
880 else if (Format == ACF_IntervalFixed32NoW)
881 {
882 const float* RESTRICT SourceBounds = (float*)TopOfStream;
883
884 float Mins[3] = {0.0f, 0.0f, 0.0f};
885 float Ranges[3] = {0.0f, 0.0f, 0.0f};
886
887 if (FormatFlags & 1)
888 {
889 Mins[0] = *SourceBounds++;
890 Ranges[0] = *SourceBounds++;
891 }
892 if (FormatFlags & 2)
893 {
894 Mins[1] = *SourceBounds++;
895 Ranges[1] = *SourceBounds++;
896 }
897 if (FormatFlags & 4)
898 {
899 Mins[2] = *SourceBounds++;
900 Ranges[2] = *SourceBounds++;
901 }
902
903 Out = FVectorIntervalFixed32NoW::ToVector<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
904 }
905 else if (Format == ACF_Fixed48NoW)
906 {
907 const uint16* RESTRICT TypedKeyData = (const uint16*)KeyData;
908 if (FormatFlags & 1)
909 {
910 Out.X = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
911 }
912 else
913 {
914 Out.X = 0.0f;
915 }
916
917 if (FormatFlags & 2)
918 {
919 Out.Y = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
920 }
921 else
922 {
923 Out.Y = 0.0f;
924 }
925
926 if (FormatFlags & 4)
927 {
928 Out.Z = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
929 }
930 else
931 {
932 Out.Z = 0.0f;
933 }
934 }
935 else if ( Format == ACF_Identity )
936 {
938 }
939 else
940 {
941 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)Format );
942 // Silence compilers warning about a value potentially not being assigned.
944 }
945 }
946
948 template<bool bIsDataAligned = true>
949 static inline void DecompressRotation(int32 Format, int32 FormatFlags, FQuat4f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
950 {
951 if (Format == ACF_Fixed48NoW)
952 {
953 const uint16* RESTRICT TypedKeyData = (const uint16*)KeyData;
954
955 const float Xa = (FormatFlags & 1) ? (float)(bIsDataAligned ? (*TypedKeyData++) : AnimationCompressionUtils::UnalignedRead<uint16>(TypedKeyData++)) : 32767.0f;
956 const float Ya = (FormatFlags & 2) ? (float)(bIsDataAligned ? (*TypedKeyData++) : AnimationCompressionUtils::UnalignedRead<uint16>(TypedKeyData++)) : 32767.0f;
957 const float Za = (FormatFlags & 4) ? (float)(bIsDataAligned ? (*TypedKeyData++) : AnimationCompressionUtils::UnalignedRead<uint16>(TypedKeyData++)) : 32767.0f;
958
959 const float X = (Xa - 32767.0f) * 3.0518509475997192297128208258309e-5f;
960 const float XX = X*X;
961 const float Y = (Ya - 32767.0f) * 3.0518509475997192297128208258309e-5f;
962 const float YY = Y*Y;
963 const float Z = (Za - 32767.0f) * 3.0518509475997192297128208258309e-5f;
964 const float ZZ = Z*Z;
965
966 const float WSquared = 1.0f - XX - YY - ZZ;
967
968 const float W = FMath::FloatSelect(WSquared, FMath::Sqrt(WSquared), 0.0f);
969
970 Out = FQuat4f(X, Y, Z, W);
971 }
972 else if (Format == ACF_Float96NoW)
973 {
974 Out = FQuatFloat96NoW::ToQuat<bIsDataAligned>((const float*)KeyData);
975 }
976 else if ( Format == ACF_IntervalFixed32NoW )
977 {
978 const float* RESTRICT SourceBounds = (float*)TopOfStream;
979
980 float Mins[3] = {0.0f, 0.0f, 0.0f};
981 float Ranges[3] = {0.0f, 0.0f, 0.0f};
982
983 if (FormatFlags & 1)
984 {
985 Mins[0] = *SourceBounds++;
986 Ranges[0] = *SourceBounds++;
987 }
988 if (FormatFlags & 2)
989 {
990 Mins[1] = *SourceBounds++;
991 Ranges[1] = *SourceBounds++;
992 }
993 if (FormatFlags & 4)
994 {
995 Mins[2] = *SourceBounds++;
996 Ranges[2] = *SourceBounds++;
997 }
998
999 Out = FQuatIntervalFixed32NoW::ToQuat<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
1000 }
1001 else if ( Format == ACF_Float32NoW )
1002 {
1003 Out = FQuatFloat32NoW::ToQuat<bIsDataAligned>((const uint32*)KeyData);
1004 }
1005 else if (Format == ACF_Fixed32NoW)
1006 {
1007 Out = FQuatFixed32NoW::ToQuat<bIsDataAligned>((const uint32*)KeyData);
1008 }
1009 else if ( Format == ACF_Identity )
1010 {
1011 Out = FQuat4f::Identity;
1012 }
1013 else
1014 {
1015 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)Format );
1016 Out = FQuat4f::Identity;
1017 }
1018 }
1019
1021 template<bool bIsDataAligned = true>
1022 static inline void DecompressScale(int32 Format, int32 FormatFlags, FVector3f& Out, const uint8* RESTRICT TopOfStream, const uint8* RESTRICT KeyData)
1023 {
1024 if( Format == ACF_Float96NoW )
1025 {
1026 // Legacy Format, all components stored
1027 if( (FormatFlags & 7) == 0 )
1028 {
1029 Out = bIsDataAligned ? *((FVector3f*)KeyData) : AnimationCompressionUtils::UnalignedRead<FVector3f>(KeyData);
1030 }
1031 // Stored per components
1032 else
1033 {
1034 const float* RESTRICT TypedKeyData = (const float*)KeyData;
1035 if (FormatFlags & 1)
1036 {
1037 Out.X = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
1038 }
1039 else
1040 {
1041 Out.X = 0.0f;
1042 }
1043
1044 if (FormatFlags & 2)
1045 {
1046 Out.Y = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
1047 }
1048 else
1049 {
1050 Out.Y = 0.0f;
1051 }
1052
1053 if (FormatFlags & 4)
1054 {
1055 Out.Z = bIsDataAligned ? *TypedKeyData++ : AnimationCompressionUtils::UnalignedRead<float>(TypedKeyData++);
1056 }
1057 else
1058 {
1059 Out.Z = 0.0f;
1060 }
1061 }
1062 }
1063 else if (Format == ACF_IntervalFixed32NoW)
1064 {
1065 const float* RESTRICT SourceBounds = (float*)TopOfStream;
1066
1067 float Mins[3] = {0.0f, 0.0f, 0.0f};
1068 float Ranges[3] = {0.0f, 0.0f, 0.0f};
1069
1070 if (FormatFlags & 1)
1071 {
1072 Mins[0] = *SourceBounds++;
1073 Ranges[0] = *SourceBounds++;
1074 }
1075 if (FormatFlags & 2)
1076 {
1077 Mins[1] = *SourceBounds++;
1078 Ranges[1] = *SourceBounds++;
1079 }
1080 if (FormatFlags & 4)
1081 {
1082 Mins[2] = *SourceBounds++;
1083 Ranges[2] = *SourceBounds++;
1084 }
1085
1086 Out = FVectorIntervalFixed32NoW::ToVector<bIsDataAligned>(Mins, Ranges, (const uint32*)KeyData);
1087 }
1088 else if (Format == ACF_Fixed48NoW)
1089 {
1090 const uint16* RESTRICT TypedKeyData = (const uint16*)KeyData;
1091 if (FormatFlags & 1)
1092 {
1093 Out.X = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
1094 }
1095 else
1096 {
1097 Out.X = 0.0f;
1098 }
1099
1100 if (FormatFlags & 2)
1101 {
1102 Out.Y = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
1103 }
1104 else
1105 {
1106 Out.Y = 0.0f;
1107 }
1108
1109 if (FormatFlags & 4)
1110 {
1111 Out.Z = FAnimationCompression_PerTrackUtils::DecompressFixed16<AnimationCompressionUtils::LogScale>(*TypedKeyData++);
1112 }
1113 else
1114 {
1115 Out.Z = 0.0f;
1116 }
1117 }
1118 else if ( Format == ACF_Identity )
1119 {
1121 }
1122 else
1123 {
1124 UE_LOG(LogAnimation, Fatal, TEXT("%i: unknown or unsupported animation compression format"), (int32)Format );
1125 // Silence compilers warning about a value potentially not being assigned.
1127 }
1128 }
1129};
1130
1131template <>
1132inline float FAnimationCompression_PerTrackUtils::DecompressFixed16<0>(uint16 Value)
1133{
1134 return ((int32)Value - 32767) * 3.0518509475997192297128208258309e-5f;
1135}
const uint8 PerTrackNumComponentTable[ACF_MAX *8]
Definition AnimEncoding.cpp:65
const int32 CompressedRotationStrides[ACF_MAX]
Definition AnimEncoding.cpp:38
@ ACF_Fixed32NoW
Definition AnimEnums.h:75
@ ACF_Float32NoW
Definition AnimEnums.h:76
@ ACF_Float96NoW
Definition AnimEnums.h:72
@ ACF_None
Definition AnimEnums.h:71
@ ACF_Fixed48NoW
Definition AnimEnums.h:73
@ ACF_IntervalFixed32NoW
Definition AnimEnums.h:74
@ ACF_Identity
Definition AnimEnums.h:77
void DecompressScale(FVector3f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:659
#define Quant16BitOffs
Definition AnimationCompression.h:28
#define Quant11BitOffs
Definition AnimationCompression.h:36
#define Quant16BitDiv
Definition AnimationCompression.h:26
#define Quant10BitFactor
Definition AnimationCompression.h:31
#define Quant10BitOffs
Definition AnimationCompression.h:32
#define Quant16BitFactor
Definition AnimationCompression.h:27
#define Quant11BitDiv
Definition AnimationCompression.h:34
void DecompressTranslation(FVector3f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:622
#define Quant11BitFactor
Definition AnimationCompression.h:35
void DecompressRotation(FQuat4f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:566
#define Quant10BitDiv
Definition AnimationCompression.h:30
#define check(expr)
Definition AssertionMacros.h:314
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define RESTRICT
Definition Platform.h:706
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
DIRECTLINK_API Display
Definition DirectLinkLog.h:8
#define X(Name, Desc)
Definition FormatStringSan.h:47
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:12
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
Definition GenericPlatformCompilerPreSetup.h:8
#define UE_REAL_TO_FLOAT(argument)
Definition LargeWorldCoordinates.h:30
#define DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, CompileTimeVerbosity)
Definition LogMacros.h:361
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
UE::Math::TVector< float > FVector3f
Definition MathFwd.h:73
UE::Math::TQuat< float > FQuat4f
Definition MathFwd.h:76
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
memcpy(InputBufferBase, BinkBlocksData, BinkBlocksSize)
uint8_t uint8
Definition binka_ue_file_header.h:8
uint16_t uint16
Definition binka_ue_file_header.h:7
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition AnimationCompression.h:693
static uint16 CompressFixed16(float Value, int32 Log2MaxValue=0)
Definition AnimationCompression.h:709
static int32 MakeHeader(const int32 NumKeys, const int32 KeyFormat, const int32 KeyFlags, bool bReallyNeedsFrameTable)
Definition AnimationCompression.h:740
static int32 GetKeyCountFromHeader(int32 Header)
Definition AnimationCompression.h:751
static void GetAllSizesFromFormat(int32 KeyFormat, int32 FormatFlags, int32 &KeyComponentCount, int32 &KeyComponentSize, int32 &FixedComponentCount, int32 &FixedComponentSize)
Definition AnimationCompression.h:762
static void DecompressTranslation(int32 Format, int32 FormatFlags, FVector3f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:839
static void GetByteSizesFromFormat(int32 KeyFormat, int32 FormatFlags, int32 &BytesPerKey, int32 &FixedBytes)
Definition AnimationCompression.h:789
static float DecompressFixed16(uint16 Value)
Definition AnimationCompression.h:725
static void DecompressRotation(int32 Format, int32 FormatFlags, FQuat4f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:949
static void DecomposeHeader(int32 Header, int32 &KeyFormat, int32 &NumKeys, int32 &FormatFlags)
Definition AnimationCompression.h:809
static void DecompressScale(int32 Format, int32 FormatFlags, FVector3f &Out, const uint8 *RESTRICT TopOfStream, const uint8 *RESTRICT KeyData)
Definition AnimationCompression.h:1022
static void DecomposeHeader(int32 Header, int32 &KeyFormat, int32 &NumKeys, int32 &FormatFlags, int32 &BytesPerKey, int32 &FixedBytes)
Definition AnimationCompression.h:827
Definition Archive.h:1208
Definition AnimationCompression.h:151
FQuatFixed32NoW()
Definition AnimationCompression.h:155
void ToQuat(FQuat4f &Out) const
Definition AnimationCompression.h:207
uint32 Packed
Definition AnimationCompression.h:153
static FQuat4f ToQuat(const uint32 *PackedValue)
Definition AnimationCompression.h:186
void FromQuat(const FQuat4f &Quat)
Definition AnimationCompression.h:163
FQuatFixed32NoW(const FQuat4f &Quat)
Definition AnimationCompression.h:158
friend FArchive & operator<<(FArchive &Ar, FQuatFixed32NoW &Quat)
Definition AnimationCompression.h:212
Definition AnimationCompression.h:97
uint16 Y
Definition AnimationCompression.h:100
FQuatFixed48NoW(const FQuat4f &Quat)
Definition AnimationCompression.h:106
FQuatFixed48NoW()
Definition AnimationCompression.h:103
void FromQuat(const FQuat4f &Quat)
Definition AnimationCompression.h:111
friend FArchive & operator<<(FArchive &Ar, FQuatFixed48NoW &Quat)
Definition AnimationCompression.h:141
void ToQuat(FQuat4f &Out) const
Definition AnimationCompression.h:128
uint16 X
Definition AnimationCompression.h:99
uint16 Z
Definition AnimationCompression.h:101
Definition AnimationCompression.h:477
static FQuat4f ToQuat(const uint32 *PackedValue)
Definition AnimationCompression.h:515
FQuatFloat32NoW()
Definition AnimationCompression.h:481
uint32 Packed
Definition AnimationCompression.h:479
void FromQuat(const FQuat4f &Quat)
Definition AnimationCompression.h:489
FQuatFloat32NoW(const FQuat4f &Quat)
Definition AnimationCompression.h:484
friend FArchive & operator<<(FArchive &Ar, FQuatFloat32NoW &Quat)
Definition AnimationCompression.h:544
void ToQuat(FQuat4f &Out) const
Definition AnimationCompression.h:539
Definition AnimationCompression.h:220
float X
Definition AnimationCompression.h:226
float XYZ[3]
Definition AnimationCompression.h:232
FQuatFloat96NoW(const FQuat4f &Quat)
Definition AnimationCompression.h:238
FQuatFloat96NoW(float InX, float InY, float InZ)
Definition AnimationCompression.h:243
void FromQuat(const FQuat4f &Quat)
Definition AnimationCompression.h:249
void ToQuat(FQuat4f &Out) const
Definition AnimationCompression.h:276
float Y
Definition AnimationCompression.h:227
static FQuat4f ToQuat(const float *Values)
Definition AnimationCompression.h:266
float Z
Definition AnimationCompression.h:228
friend FArchive & operator<<(FArchive &Ar, FQuatFloat96NoW &Quat)
Definition AnimationCompression.h:283
Definition AnimationCompression.h:404
uint32 Packed
Definition AnimationCompression.h:406
void ToQuat(FQuat4f &Out, const float *Mins, const float *Ranges) const
Definition AnimationCompression.h:464
friend FArchive & operator<<(FArchive &Ar, FQuatIntervalFixed32NoW &Quat)
Definition AnimationCompression.h:469
FQuatIntervalFixed32NoW()
Definition AnimationCompression.h:408
FQuatIntervalFixed32NoW(const FQuat4f &Quat, const float *Mins, const float *Ranges)
Definition AnimationCompression.h:411
static FQuat4f ToQuat(const float *Mins, const float *Ranges, const uint32 *PackedValue)
Definition AnimationCompression.h:443
void FromQuat(const FQuat4f &Quat, const float *Mins, const float *Ranges)
Definition AnimationCompression.h:416
Definition AnimationCompression.h:295
FVectorFixed48(const FVector3f &Vec)
Definition AnimationCompression.h:304
FVectorFixed48()
Definition AnimationCompression.h:301
void ToVector(FVector3f &Out) const
Definition AnimationCompression.h:318
uint16 X
Definition AnimationCompression.h:297
uint16 Z
Definition AnimationCompression.h:299
uint16 Y
Definition AnimationCompression.h:298
void FromVector(const FVector3f &Vec)
Definition AnimationCompression.h:309
friend FArchive & operator<<(FArchive &Ar, FVectorFixed48 &Vec)
Definition AnimationCompression.h:329
Definition AnimationCompression.h:339
FVectorIntervalFixed32NoW()
Definition AnimationCompression.h:343
uint32 Packed
Definition AnimationCompression.h:341
friend FArchive & operator<<(FArchive &Ar, FVectorIntervalFixed32NoW &Value)
Definition AnimationCompression.h:395
FVectorIntervalFixed32NoW(const FVector3f &Value, const float *Mins, const float *Ranges)
Definition AnimationCompression.h:346
void FromVector(const FVector3f &Value, const float *Mins, const float *Ranges)
Definition AnimationCompression.h:351
void ToVector(FVector3f &Out, const float *Mins, const float *Ranges) const
Definition AnimationCompression.h:390
static FVector3f ToVector(const float *Mins, const float *Ranges, const uint32 *PackedValue)
Definition AnimationCompression.h:370
Definition FloatPacker.h:46
PackedType Encode(FloatType Value) const
Definition FloatPacker.h:64
FloatType Decode(PackedType Value) const
Definition FloatPacker.h:110
Definition AnimationCompression.h:39
FQuat4d Interpolate< FQuat4d >(const FQuat4d &A, const FQuat4d &B, float Alpha)
Definition AnimationCompression.h:81
T Interpolate(const T &A, const T &B, float Alpha)
Definition AnimationCompression.h:63
FVector3d Interpolate< FVector3d >(const FVector3d &A, const FVector3d &B, float Alpha)
Definition AnimationCompression.h:75
FVector3f Interpolate< FVector3f >(const FVector3f &A, const FVector3f &B, float Alpha)
Definition AnimationCompression.h:71
FQuat4f Interpolate< FQuat4f >(const FQuat4f &A, const FQuat4f &B, float Alpha)
Definition AnimationCompression.h:88
ValueType UnalignedRead(const void *Ptr)
Definition AnimationCompression.h:44
static constexpr UE_FORCEINLINE_HINT T Lerp(const T &A, const T &B, const U &Alpha)
Definition UnrealMathUtility.h:1116
static TQuat< double > FastLerp(const TQuat< double > &A, const TQuat< double > &B, const double Alpha)
Definition Quat.h:1373
T W
Definition Quat.h:58
T Y
Definition Quat.h:52
T Z
Definition Quat.h:55
static CORE_API const TQuat< float > Identity
Definition Quat.h:63
T X
Definition Quat.h:49
void Normalize(T Tolerance=UE_SMALL_NUMBER)
Definition Quat.h:1107
T Z
Definition Vector.h:68
T Y
Definition Vector.h:65
static CORE_API const TVector< float > ZeroVector
Definition Vector.h:79
T X
Definition Vector.h:62