mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
172 lines
3.9 KiB
C#
172 lines
3.9 KiB
C#
using AssetRipper.Numerics;
|
|
using AssetRipper.SourceGenerated.Subclasses.PackedBitVector_Quaternionf;
|
|
using System.Numerics;
|
|
|
|
namespace AssetRipper.SourceGenerated.Extensions;
|
|
|
|
public static class PackedQuatVectorExtensions
|
|
{
|
|
public static void CopyValuesFrom(this PackedBitVector_Quaternionf instance, PackedBitVector_Quaternionf source)
|
|
{
|
|
instance.NumItems = source.NumItems;
|
|
instance.Data = source.Data.ToArray();
|
|
}
|
|
|
|
public static void Pack(this PackedBitVector_Quaternionf packedVector, ReadOnlySpan<Quaternion> inputData)
|
|
{
|
|
packedVector.NumItems = (uint)inputData.Length;
|
|
packedVector.Data = new byte[inputData.Length * 4];
|
|
|
|
int bitIndex = 0;
|
|
int byteIndex = 0;
|
|
|
|
for (int i = 0; i < inputData.Length; i++)
|
|
{
|
|
Quaternion q = inputData[i];
|
|
byte flags = unchecked((byte)(q.X < 0 ? 4 : 0));
|
|
|
|
float max = Math.Abs(q.X);
|
|
if (Math.Abs(q.Y) > max)
|
|
{
|
|
max = Math.Abs(q.Y);
|
|
flags = 1;
|
|
if (q.Y < 0)
|
|
{
|
|
flags |= 4;
|
|
}
|
|
}
|
|
if (Math.Abs(q.Z) > max)
|
|
{
|
|
max = Math.Abs(q.Z);
|
|
flags = 2;
|
|
if (q.Z < 0)
|
|
{
|
|
flags |= 4;
|
|
}
|
|
}
|
|
if (Math.Abs(q.W) > max)
|
|
{
|
|
max = Math.Abs(q.W);
|
|
flags = 3;
|
|
if (q.W < 0)
|
|
{
|
|
flags |= 4;
|
|
}
|
|
}
|
|
int bitOffset = 0;
|
|
while (bitOffset < 3)
|
|
{
|
|
packedVector.Data[byteIndex] |= unchecked((byte)(flags >> bitOffset << bitIndex));
|
|
int num = Math.Min(3 - bitOffset, 8 - bitIndex);
|
|
bitIndex += num;
|
|
bitOffset += num;
|
|
if (bitIndex == 8)
|
|
{
|
|
byteIndex++;
|
|
bitIndex = 0;
|
|
}
|
|
}
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if ((flags & 3) != j)
|
|
{
|
|
int bitSize = ((flags & 3) + 1) % 4 == j ? 9 : 10;
|
|
double scaled = (q.GetAt(j) + 1d) * 0.5d;
|
|
if (scaled < 0)
|
|
{
|
|
scaled = 0d;
|
|
}
|
|
else if (scaled > 1)
|
|
{
|
|
scaled = 1d;
|
|
}
|
|
|
|
float f = BitConverter.Int32BitsToSingle((1 << bitSize) - 1);
|
|
uint x = BitConverter.SingleToUInt32Bits((float)(scaled * f));
|
|
|
|
bitOffset = 0;
|
|
while (bitOffset < bitSize)
|
|
{
|
|
packedVector.Data[byteIndex] |= unchecked((byte)(x >> bitOffset << bitIndex));
|
|
int read = Math.Min(bitSize - bitOffset, 8 - bitIndex);
|
|
bitIndex += read;
|
|
bitOffset += read;
|
|
if (bitIndex == 8)
|
|
{
|
|
byteIndex++;
|
|
bitIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Quaternion[] Unpack(this PackedBitVector_Quaternionf packedVector)
|
|
{
|
|
int bitIndex = 0;
|
|
int byteIndex = 0;
|
|
Quaternion[] buffer = new Quaternion[packedVector.NumItems];
|
|
for (int i = 0; i < packedVector.NumItems; i++)
|
|
{
|
|
uint flags = 0;
|
|
int bitOffset = 0;
|
|
while (bitOffset < 3)
|
|
{
|
|
flags |= unchecked((uint)(packedVector.Data[byteIndex] >> bitIndex << bitOffset));
|
|
int read = Math.Min(3 - bitOffset, 8 - bitIndex);
|
|
bitIndex += read;
|
|
bitOffset += read;
|
|
if (bitIndex == 8)
|
|
{
|
|
byteIndex++;
|
|
bitIndex = 0;
|
|
}
|
|
}
|
|
flags &= 7;
|
|
|
|
double sum = 0;
|
|
Quaternion quaternion = default;
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
if ((flags & 3) != j)
|
|
{
|
|
int bitSize = ((flags & 3) + 1) % 4 == j ? 9 : 10;
|
|
|
|
uint value = 0;
|
|
bitOffset = 0;
|
|
while (bitOffset < bitSize)
|
|
{
|
|
value |= unchecked((uint)(packedVector.Data[byteIndex] >> bitIndex << bitOffset));
|
|
int num = Math.Min(bitSize - bitOffset, 8 - bitIndex);
|
|
bitIndex += num;
|
|
bitOffset += num;
|
|
if (bitIndex == 8)
|
|
{
|
|
byteIndex++;
|
|
bitIndex = 0;
|
|
}
|
|
}
|
|
value &= unchecked((uint)((1 << bitSize) - 1));
|
|
|
|
// final value's range is [-1.0f : 1.0f]
|
|
double halfMaxValue = 0.5d * ((1 << bitSize) - 1);
|
|
double quaternion_j = value / halfMaxValue - 1.0d;
|
|
quaternion.SetAt(j, (float)quaternion_j);
|
|
sum += quaternion_j * quaternion_j;
|
|
}
|
|
}
|
|
|
|
int lastComponent = unchecked((int)(flags & 3));
|
|
quaternion.SetAt(lastComponent, (float)Math.Sqrt(1.0d - sum));
|
|
if ((flags & 4) != 0)
|
|
{
|
|
quaternion.FlipSignAt(lastComponent);
|
|
}
|
|
|
|
buffer[i] = quaternion;
|
|
}
|
|
return buffer;
|
|
}
|
|
}
|