Last active
October 1, 2022 16:30
-
-
Save James-Frowen/d226116941fb22c8b4720ec66b126971 to your computer and use it in GitHub Desktop.
Write/Read Compressed Vector3 for mirror
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class PositionCompression | |
| { | |
| public struct CompressFloat | |
| { | |
| public readonly float minFloat; | |
| public readonly float maxFloat; | |
| public readonly uint minUint; | |
| public readonly uint maxUint; | |
| public readonly int bitCount; | |
| public readonly uint readMask; | |
| public readonly ulong readMaskLong; | |
| public CompressFloat(float min, float max, float precision) | |
| { | |
| minFloat = min; | |
| maxFloat = max; | |
| float range = max - min; | |
| float rangeUint = range / precision; | |
| float logBase10 = Mathf.Log10(rangeUint); | |
| float logOf2 = Mathf.Log10(2); | |
| float logBase2 = logBase10 / logOf2; | |
| bitCount = Mathf.CeilToInt(logBase2); | |
| minUint = 0u; | |
| maxUint = (1u << bitCount) - 1u; | |
| readMask = ~(maxUint + 1u); | |
| readMaskLong = ~(maxUint + 1ul); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public uint Compress(float value) | |
| { | |
| return Compression.ScaleToUInt(value, minFloat, maxFloat, minUint, maxUint); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public float Decompress(uint value) | |
| { | |
| return Compression.ScaleFromUInt(value, minFloat, maxFloat, minUint, maxUint); | |
| } | |
| } | |
| readonly CompressFloat x; | |
| readonly CompressFloat y; | |
| readonly CompressFloat z; | |
| readonly int bitCount; | |
| public PositionCompression(Bounds bounds, float precision) : this(bounds, Vector3.one * precision) { } | |
| public PositionCompression(Bounds bounds, Vector3 precision) | |
| { | |
| Vector3 min = bounds.min; | |
| Vector3 max = bounds.max; | |
| x = new CompressFloat(min.x, max.x, precision.x); | |
| y = new CompressFloat(min.y, max.y, precision.y); | |
| z = new CompressFloat(min.z, max.z, precision.z); | |
| bitCount = x.bitCount + y.bitCount + z.bitCount; | |
| const int maxBitCount = sizeof(ulong) * 8; | |
| if (bitCount > maxBitCount) | |
| { | |
| throw new ArgumentException($"Compressing to sizes over {maxBitCount}"); | |
| } | |
| } | |
| public void Compress(NetworkWriter writer, Vector3 value) | |
| { | |
| uint a = x.Compress(value.x); | |
| uint b = y.Compress(value.y); | |
| uint c = z.Compress(value.z); | |
| if (bitCount <= 32) | |
| { | |
| uint s = a | b << x.bitCount | c << (x.bitCount + y.bitCount); | |
| if (bitCount <= 16) | |
| { | |
| writer.WriteUInt16((ushort)s); | |
| } | |
| else if (bitCount <= 24) | |
| { | |
| writer.WriteUInt16((ushort)s); | |
| writer.WriteByte((byte)(s >> 16)); | |
| } | |
| else // 32 | |
| { | |
| writer.WriteUInt32(s); | |
| } | |
| } | |
| else | |
| { | |
| ulong s = a | b << x.bitCount | c << (x.bitCount + y.bitCount); | |
| if (bitCount <= 40) | |
| { | |
| writer.WriteUInt32((uint)s); | |
| writer.WriteByte((byte)(s >> 32)); | |
| } | |
| else if (bitCount <= 48) | |
| { | |
| writer.WriteUInt32((uint)s); | |
| writer.WriteUInt16((ushort)(s >> 32)); | |
| } | |
| else if (bitCount <= 56) | |
| { | |
| writer.WriteUInt32((uint)s); | |
| writer.WriteUInt16((ushort)(s >> 32)); | |
| writer.WriteByte((byte)(s >> 48)); | |
| } | |
| else // 64 | |
| { | |
| writer.WriteUInt64(s); | |
| } | |
| } | |
| } | |
| public Vector3 Decompress(NetworkReader reader) | |
| { | |
| uint a; | |
| uint b; | |
| uint c; | |
| if (bitCount <= 32) | |
| { | |
| uint s; | |
| if (bitCount <= 16) | |
| { | |
| s = reader.ReadUInt16(); | |
| } | |
| else if (bitCount <= 24) | |
| { | |
| uint s1 = reader.ReadUInt16(); | |
| uint s2 = reader.ReadByte(); | |
| s = s1 | s2 << 16; | |
| } | |
| else // 32 | |
| { | |
| s = reader.ReadUInt32(); | |
| } | |
| a = x.readMask & s; | |
| b = y.readMask & s >> x.bitCount; | |
| c = z.readMask & s >> (x.bitCount + y.bitCount); | |
| } | |
| else | |
| { | |
| ulong s; | |
| ulong s1 = reader.ReadUInt32(); | |
| if (bitCount <= 40) | |
| { | |
| ulong s2 = reader.ReadByte(); | |
| s = s1 | s2 << 32; | |
| } | |
| else if (bitCount <= 48) | |
| { | |
| ulong s2 = reader.ReadUInt16(); | |
| s = s1 | s2 << 32; | |
| } | |
| else if (bitCount <= 56) | |
| { | |
| ulong s2 = reader.ReadUInt16(); | |
| ulong s3 = reader.ReadByte(); | |
| s = s1 | s2 << 32 | s3 << 48; | |
| } | |
| else // 64 | |
| { | |
| s = reader.ReadUInt64(); | |
| } | |
| a = (uint)(x.readMaskLong & s); | |
| b = (uint)(y.readMaskLong & s >> x.bitCount); | |
| c = (uint)(z.readMaskLong & s >> (x.bitCount + y.bitCount)); | |
| } | |
| return new Vector3( | |
| x.Decompress(a), | |
| y.Decompress(b), | |
| z.Decompress(c)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment