#ifndef UNITY_PERCEPTION_PACKING_INCLUDED
#define UNITY_PERCEPTION_PACKING_INCLUDED

#define real float
#define real2 float2
#define real3 float3
#define real4 float4

// Packs an integer stored using at most 'numBits' into a [0..1] real.
real PackInt(uint i, uint numBits)
{
    uint maxInt = (1u << numBits) - 1u;
    return saturate(i * rcp(maxInt));
}

// Unpacks a [0..1] real into an integer of size 'numBits'.
uint UnpackInt(real f, uint numBits)
{
    uint maxInt = (1u << numBits) - 1u;
    return (uint)(f * maxInt + 0.5); // Round instead of truncating
}

#ifndef INTRINSIC_BITFIELD_EXTRACT
// Unsigned integer bit field extraction.
// Note that the intrinsic itself generates a vector instruction.
// Wrap this function with WaveReadLaneFirst() to get scalar output.
uint BitFieldExtract(uint data, uint offset, uint numBits)
{
    uint mask = (1u << numBits) - 1u;
    return (data >> offset) & mask;
}
#endif // INTRINSIC_BITFIELD_EXTRACT

//-----------------------------------------------------------------------------
// Float packing
//-----------------------------------------------------------------------------

// src must be between 0.0 and 1.0
uint PackFloatToUInt(real src, uint offset, uint numBits)
{
    return UnpackInt(src, numBits) << offset;
}

real UnpackUIntToFloat(uint src, uint offset, uint numBits)
{
    uint maxInt = (1u << numBits) - 1u;
    return real(BitFieldExtract(src, offset, numBits)) * rcp(maxInt);
}

#endif // UNITY_PACKING_INCLUDED