| using System; |
| using System.Runtime.CompilerServices; |
| using Unity.Collections.LowLevel.Unsafe; |
| using UnityEngine.InputSystem.Utilities; |
|
|
| |
|
|
| |
|
|
| |
| |
| |
|
|
| |
|
|
| |
| |
|
|
| |
| |
|
|
| namespace UnityEngine.InputSystem.LowLevel |
| { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public unsafe struct InputStateBlock |
| { |
| public const uint InvalidOffset = 0xffffffff; |
| public const uint AutomaticOffset = 0xfffffffe; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatInvalid = new FourCC(0); |
| internal const int kFormatInvalid = 0; |
|
|
| |
| |
| |
| |
| |
| public static readonly FourCC FormatBit = new FourCC('B', 'I', 'T'); |
| internal const int kFormatBit = 'B' << 24 | 'I' << 16 | 'T' << 8 | ' '; |
|
|
| |
| |
| |
| |
| |
| |
| public static readonly FourCC FormatSBit = new FourCC('S', 'B', 'I', 'T'); |
| internal const int kFormatSBit = 'S' << 24 | 'B' << 16 | 'I' << 8 | 'T'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatInt = new FourCC('I', 'N', 'T'); |
| internal const int kFormatInt = 'I' << 24 | 'N' << 16 | 'T' << 8 | ' '; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatUInt = new FourCC('U', 'I', 'N', 'T'); |
| internal const int kFormatUInt = 'U' << 24 | 'I' << 16 | 'N' << 8 | 'T'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatShort = new FourCC('S', 'H', 'R', 'T'); |
| internal const int kFormatShort = 'S' << 24 | 'H' << 16 | 'R' << 8 | 'T'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatUShort = new FourCC('U', 'S', 'H', 'T'); |
| internal const int kFormatUShort = 'U' << 24 | 'S' << 16 | 'H' << 8 | 'T'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatByte = new FourCC('B', 'Y', 'T', 'E'); |
| internal const int kFormatByte = 'B' << 24 | 'Y' << 16 | 'T' << 8 | 'E'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatSByte = new FourCC('S', 'B', 'Y', 'T'); |
| internal const int kFormatSByte = 'S' << 24 | 'B' << 16 | 'Y' << 8 | 'T'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatLong = new FourCC('L', 'N', 'G'); |
| internal const int kFormatLong = 'L' << 24 | 'N' << 16 | 'G' << 8 | ' '; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatULong = new FourCC('U', 'L', 'N', 'G'); |
| internal const int kFormatULong = 'U' << 24 | 'L' << 16 | 'N' << 8 | 'G'; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatFloat = new FourCC('F', 'L', 'T'); |
| internal const int kFormatFloat = 'F' << 24 | 'L' << 16 | 'T' << 8 | ' '; |
|
|
| |
| |
| |
| |
| public static readonly FourCC FormatDouble = new FourCC('D', 'B', 'L'); |
| internal const int kFormatDouble = 'D' << 24 | 'B' << 16 | 'L' << 8 | ' '; |
|
|
| |
| public static readonly FourCC FormatVector2 = new FourCC('V', 'E', 'C', '2'); |
| internal const int kFormatVector2 = 'V' << 24 | 'E' << 16 | 'C' << 8 | '2'; |
| public static readonly FourCC FormatVector3 = new FourCC('V', 'E', 'C', '3'); |
| internal const int kFormatVector3 = 'V' << 24 | 'E' << 16 | 'C' << 8 | '3'; |
| public static readonly FourCC FormatQuaternion = new FourCC('Q', 'U', 'A', 'T'); |
| internal const int kFormatQuaternion = 'Q' << 24 | 'U' << 16 | 'A' << 8 | 'T'; |
| public static readonly FourCC FormatVector2Short = new FourCC('V', 'C', '2', 'S'); |
| public static readonly FourCC FormatVector3Short = new FourCC('V', 'C', '3', 'S'); |
| public static readonly FourCC FormatVector2Byte = new FourCC('V', 'C', '2', 'B'); |
| public static readonly FourCC FormatVector3Byte = new FourCC('V', 'C', '3', 'B'); |
| public static readonly FourCC FormatPose = new FourCC('P', 'o', 's', 'e'); |
| internal const int kFormatPose = 'P' << 24 | 'o' << 16 | 's' << 8 | 'e'; |
|
|
| public static int GetSizeOfPrimitiveFormatInBits(FourCC type) |
| { |
| if (type == FormatBit || type == FormatSBit) |
| return 1; |
| if (type == FormatInt || type == FormatUInt) |
| return 4 * 8; |
| if (type == FormatShort || type == FormatUShort) |
| return 2 * 8; |
| if (type == FormatByte || type == FormatSByte) |
| return 1 * 8; |
| if (type == FormatLong || type == FormatULong) |
| return 8 * 8; |
| if (type == FormatFloat) |
| return 4 * 8; |
| if (type == FormatDouble) |
| return 8 * 8; |
| if (type == FormatVector2) |
| return 2 * 4 * 8; |
| if (type == FormatVector3) |
| return 3 * 4 * 8; |
| if (type == FormatQuaternion) |
| return 4 * 4 * 8; |
| if (type == FormatVector2Short) |
| return 2 * 2 * 8; |
| if (type == FormatVector3Short) |
| return 3 * 2 * 8; |
| if (type == FormatVector2Byte) |
| return 2 * 1 * 8; |
| if (type == FormatVector3Byte) |
| return 3 * 1 * 8; |
| return -1; |
| } |
|
|
| public static FourCC GetPrimitiveFormatFromType(Type type) |
| { |
| if (ReferenceEquals(type, typeof(int))) |
| return FormatInt; |
| if (ReferenceEquals(type, typeof(uint))) |
| return FormatUInt; |
| if (ReferenceEquals(type, typeof(short))) |
| return FormatShort; |
| if (ReferenceEquals(type, typeof(ushort))) |
| return FormatUShort; |
| if (ReferenceEquals(type, typeof(byte))) |
| return FormatByte; |
| if (ReferenceEquals(type, typeof(sbyte))) |
| return FormatSByte; |
| if (ReferenceEquals(type, typeof(long))) |
| return FormatLong; |
| if (ReferenceEquals(type, typeof(ulong))) |
| return FormatULong; |
| if (ReferenceEquals(type, typeof(float))) |
| return FormatFloat; |
| if (ReferenceEquals(type, typeof(double))) |
| return FormatDouble; |
| if (ReferenceEquals(type, typeof(Vector2))) |
| return FormatVector2; |
| if (ReferenceEquals(type, typeof(Vector3))) |
| return FormatVector3; |
| if (ReferenceEquals(type, typeof(Quaternion))) |
| return FormatQuaternion; |
| return new FourCC(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public FourCC format { get; set; } |
|
|
| |
| |
| |
| |
| |
| |
| public uint byteOffset |
| { |
| get => m_ByteOffset; |
| set |
| { |
| m_ByteOffset = value; |
| } |
| } |
|
|
| |
| internal uint m_ByteOffset; |
|
|
| |
| |
| public uint bitOffset { get; set; } |
|
|
| |
| |
| |
| |
| |
| public uint sizeInBits { get; set; } |
|
|
| internal uint alignedSizeInBytes => (sizeInBits + 7) >> 3; |
| internal uint effectiveByteOffset => byteOffset + (bitOffset >> 3); |
| internal uint effectiveBitOffset => byteOffset * 8 + bitOffset; |
|
|
| public int ReadInt(void* statePtr) |
| { |
| Debug.Assert(sizeInBits != 0); |
|
|
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1 : 0; |
| return (int)MemoryHelpers.ReadMultipleBitsAsUInt(valuePtr, bitOffset, sizeInBits); |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1 : -1; |
| return MemoryHelpers.ReadExcessKMultipleBitsAsInt(valuePtr, bitOffset, sizeInBits); |
| case kFormatInt: |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "INT and UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT and UINT state must be byte-aligned"); |
| if (fmt == kFormatUInt) |
| Debug.Assert(*(uint*)valuePtr <= int.MaxValue, "UINT must fit in the int"); |
| return *(int*)valuePtr; |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| return *(short*)valuePtr; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| return *(ushort*)valuePtr; |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| return *valuePtr; |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| return *(sbyte*)valuePtr; |
| |
| |
| |
| |
| |
| default: |
| throw new InvalidOperationException($"State format '{format}' is not supported as integer format"); |
| } |
| } |
|
|
| public void WriteInt(void* statePtr, int value) |
| { |
| Debug.Assert(sizeInBits != 0); |
|
|
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value != 0); |
| else |
| MemoryHelpers.WriteUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, (uint)value); |
| break; |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value > 0); |
| else |
| MemoryHelpers.WriteIntAsExcessKMultipleBits(valuePtr, bitOffset, sizeInBits, value); |
| break; |
| case kFormatInt: |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "INT and UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT and UINT state must be byte-aligned"); |
| *(int*)valuePtr = value; |
| break; |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| *(short*)valuePtr = (short)value; |
| break; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| *(ushort*)valuePtr = (ushort)value; |
| break; |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| *valuePtr = (byte)value; |
| break; |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| *(sbyte*)valuePtr = (sbyte)value; |
| break; |
| |
| |
| |
| |
| |
| default: |
| throw new Exception($"State format '{format}' is not supported as integer format"); |
| } |
| } |
|
|
| public float ReadFloat(void* statePtr) |
| { |
| Debug.Assert(sizeInBits != 0); |
|
|
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| |
| |
| |
| case kFormatBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : 0.0f; |
| return MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits); |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : -1.0f; |
| return MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits) * 2.0f - 1.0f; |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(int*)valuePtr, int.MinValue, int.MaxValue) * 2.0f - 1.0f; |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*(uint*)valuePtr, uint.MinValue, uint.MaxValue); |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(short*)valuePtr, short.MinValue, short.MaxValue) * 2.0f - 1.0f; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*(ushort*)valuePtr, ushort.MinValue, ushort.MaxValue); |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*valuePtr, byte.MinValue, byte.MaxValue); |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(sbyte*)valuePtr, sbyte.MinValue, sbyte.MaxValue) * 2.0f - 1.0f; |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| return *(float*)valuePtr; |
| case kFormatDouble: |
| Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); |
| Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); |
| return (float)*(double*)valuePtr; |
| |
| |
| |
| default: |
| throw new InvalidOperationException($"State format '{format}' is not supported as floating-point format"); |
| } |
| } |
|
|
| public void WriteFloat(void* statePtr, float value) |
| { |
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value >= 0.5f); |
| else |
| MemoryHelpers.WriteNormalizedUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, value); |
| break; |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value >= 0.0f); |
| else |
| MemoryHelpers.WriteNormalizedUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, value * 0.5f + 0.5f); |
| break; |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| *(int*)valuePtr = (int)NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, int.MinValue, int.MaxValue); |
| break; |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| *(uint*)valuePtr = NumberHelpers.NormalizedFloatToUInt(value, uint.MinValue, uint.MaxValue); |
| break; |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| *(short*)valuePtr = (short)NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, short.MinValue, short.MaxValue); |
| break; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| *(ushort*)valuePtr = (ushort)NumberHelpers.NormalizedFloatToUInt(value, ushort.MinValue, ushort.MaxValue); |
| break; |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| *valuePtr = (byte)NumberHelpers.NormalizedFloatToUInt(value, byte.MinValue, byte.MaxValue); |
| break; |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| *(sbyte*)valuePtr = (sbyte)NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, sbyte.MinValue, sbyte.MaxValue); |
| break; |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| *(float*)valuePtr = value; |
| break; |
| case kFormatDouble: |
| Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); |
| Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); |
| *(double*)valuePtr = value; |
| break; |
| |
| |
| |
| default: |
| throw new Exception($"State format '{format}' is not supported as floating-point format"); |
| } |
| } |
|
|
| internal PrimitiveValue FloatToPrimitiveValue(float value) |
| { |
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| return value >= 0.5f; |
| |
| return (int)NumberHelpers.NormalizedFloatToUInt(value, 0, (uint)((1UL << (int)sizeInBits) - 1)); |
| case kFormatSBit: |
| { |
| if (sizeInBits == 1) |
| return value >= 0.0f; |
| var minValue = (int)-(long)(1UL << ((int)sizeInBits - 1)); |
| var maxValue = (int)((1UL << ((int)sizeInBits - 1)) - 1); |
| return NumberHelpers.NormalizedFloatToInt(value, minValue, maxValue); |
| } |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| return NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, int.MinValue, int.MaxValue); |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| return NumberHelpers.NormalizedFloatToUInt(value, uint.MinValue, uint.MaxValue); |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| return (short)NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, short.MinValue, short.MaxValue); |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| return (ushort)NumberHelpers.NormalizedFloatToUInt(value, ushort.MinValue, ushort.MaxValue); |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| return (byte)NumberHelpers.NormalizedFloatToUInt(value, byte.MinValue, byte.MaxValue); |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| return (sbyte)NumberHelpers.NormalizedFloatToInt(value * 0.5f + 0.5f, sbyte.MinValue, sbyte.MaxValue); |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| return value; |
| case kFormatDouble: |
| Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); |
| Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); |
| return value; |
| |
| |
| |
| default: |
| throw new Exception($"State format '{format}' is not supported as floating-point format"); |
| } |
| } |
|
|
| |
| |
|
|
| public double ReadDouble(void* statePtr) |
| { |
| Debug.Assert(sizeInBits != 0); |
|
|
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| |
| |
| |
| case kFormatBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : 0.0f; |
| return MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits); |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| return MemoryHelpers.ReadSingleBit(valuePtr, bitOffset) ? 1.0f : -1.0f; |
| return MemoryHelpers.ReadMultipleBitsAsNormalizedUInt(valuePtr, bitOffset, sizeInBits) * 2.0f - 1.0f; |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(int*)valuePtr, int.MinValue, int.MaxValue) * 2.0f - 1.0f; |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*(uint*)valuePtr, uint.MinValue, uint.MaxValue); |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(short*)valuePtr, short.MinValue, short.MaxValue) * 2.0f - 1.0f; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*(ushort*)valuePtr, ushort.MinValue, ushort.MaxValue); |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| return NumberHelpers.UIntToNormalizedFloat(*valuePtr, byte.MinValue, byte.MaxValue); |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| return NumberHelpers.IntToNormalizedFloat(*(sbyte*)valuePtr, sbyte.MinValue, sbyte.MaxValue) * 2.0f - 1.0f; |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| return *(float*)valuePtr; |
| case kFormatDouble: |
| Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); |
| Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); |
| return *(double*)valuePtr; |
| |
| |
| |
| |
| |
| default: |
| throw new Exception($"State format '{format}' is not supported as floating-point format"); |
| } |
| } |
|
|
| public void WriteDouble(void* statePtr, double value) |
| { |
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value >= 0.5f); |
| else |
| MemoryHelpers.WriteNormalizedUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, (float)value); |
| break; |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value >= 0.0f); |
| else |
| MemoryHelpers.WriteNormalizedUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, (float)value * 0.5f + 0.5f); |
| break; |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| *(int*)valuePtr = NumberHelpers.NormalizedFloatToInt((float)value * 0.5f + 0.5f, int.MinValue, int.MaxValue); |
| break; |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| *(uint*)valuePtr = NumberHelpers.NormalizedFloatToUInt((float)value, uint.MinValue, uint.MaxValue); |
| break; |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| *(short*)valuePtr = (short)NumberHelpers.NormalizedFloatToInt((float)value * 0.5f + 0.5f, short.MinValue, short.MaxValue); |
| break; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| *(ushort*)valuePtr = (ushort)NumberHelpers.NormalizedFloatToUInt((float)value, ushort.MinValue, ushort.MaxValue); |
| break; |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| *valuePtr = (byte)NumberHelpers.NormalizedFloatToUInt((float)value, byte.MinValue, byte.MaxValue); |
| break; |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| *(sbyte*)valuePtr = (sbyte)NumberHelpers.NormalizedFloatToInt((float)value * 0.5f + 0.5f, sbyte.MinValue, sbyte.MaxValue); |
| break; |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| *(float*)valuePtr = (float)value; |
| break; |
| case kFormatDouble: |
| Debug.Assert(sizeInBits == 64, "DBL state must have sizeInBits=64"); |
| Debug.Assert(bitOffset == 0, "DBL state must be byte-aligned"); |
| *(double*)valuePtr = value; |
| break; |
| |
| |
| |
| |
| |
| default: |
| throw new InvalidOperationException($"State format '{format}' is not supported as floating-point format"); |
| } |
| } |
|
|
| public void Write(void* statePtr, PrimitiveValue value) |
| { |
| var valuePtr = (byte*)statePtr + (int)byteOffset; |
|
|
| var fmt = (int)format; |
| switch (fmt) |
| { |
| case kFormatBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value.ToBoolean()); |
| else |
| MemoryHelpers.WriteUIntAsMultipleBits(valuePtr, bitOffset, sizeInBits, value.ToUInt32()); |
| break; |
| case kFormatSBit: |
| if (sizeInBits == 1) |
| MemoryHelpers.WriteSingleBit(valuePtr, bitOffset, value.ToBoolean()); |
| else |
| |
| MemoryHelpers.WriteIntAsExcessKMultipleBits(valuePtr, bitOffset, sizeInBits, value.ToInt32()); |
| break; |
| case kFormatInt: |
| Debug.Assert(sizeInBits == 32, "INT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "INT state must be byte-aligned"); |
| *(int*)valuePtr = value.ToInt32(); |
| break; |
| case kFormatUInt: |
| Debug.Assert(sizeInBits == 32, "UINT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "UINT state must be byte-aligned"); |
| *(uint*)valuePtr = value.ToUInt32(); |
| break; |
| case kFormatShort: |
| Debug.Assert(sizeInBits == 16, "SHRT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "SHRT state must be byte-aligned"); |
| *(short*)valuePtr = value.ToInt16(); |
| break; |
| case kFormatUShort: |
| Debug.Assert(sizeInBits == 16, "USHT state must have sizeInBits=16"); |
| Debug.Assert(bitOffset == 0, "USHT state must be byte-aligned"); |
| *(ushort*)valuePtr = value.ToUInt16(); |
| break; |
| case kFormatByte: |
| Debug.Assert(sizeInBits == 8, "BYTE state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "BYTE state must be byte-aligned"); |
| *valuePtr = value.ToByte(); |
| break; |
| case kFormatSByte: |
| Debug.Assert(sizeInBits == 8, "SBYT state must have sizeInBits=8"); |
| Debug.Assert(bitOffset == 0, "SBYT state must be byte-aligned"); |
| *(sbyte*)valuePtr = value.ToSByte(); |
| break; |
| case kFormatFloat: |
| Debug.Assert(sizeInBits == 32, "FLT state must have sizeInBits=32"); |
| Debug.Assert(bitOffset == 0, "FLT state must be byte-aligned"); |
| *(float*)valuePtr = value.ToSingle(); |
| break; |
| |
| |
| |
| |
| default: |
| throw new NotImplementedException( |
| $"Writing primitive value of type '{value.type}' into state block with format '{format}'"); |
| } |
| } |
|
|
| public void CopyToFrom(void* toStatePtr, void* fromStatePtr) |
| { |
| if (bitOffset != 0 || sizeInBits % 8 != 0) |
| throw new NotImplementedException("Copying bitfields"); |
|
|
| var from = (byte*)fromStatePtr + byteOffset; |
| var to = (byte*)toStatePtr + byteOffset; |
|
|
| UnsafeUtility.MemCpy(to, from, alignedSizeInBytes); |
| } |
| } |
| } |
|
|