2023-04-10 15:02:56 +02:00
|
|
|
|
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
2022-04-02 02:48:54 +02:00
|
|
|
|
//
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// Purpose: buffer serialization/deserialization.
|
2022-04-02 02:48:54 +02:00
|
|
|
|
//
|
|
|
|
|
// $NoKeywords: $
|
|
|
|
|
//===========================================================================//
|
|
|
|
|
|
|
|
|
|
#include "tier1/bitbuf.h"
|
2023-04-10 15:02:56 +02:00
|
|
|
|
#include "mathlib/bitvec.h"
|
2024-02-21 01:10:14 +01:00
|
|
|
|
#include "public/coordsize.h"
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Precalculated bit masks for WriteUBitLong. Using these tables instead of
|
|
|
|
|
// doing the calculations gives a 33% speedup in WriteUBitLong.
|
|
|
|
|
uint32 g_BitWriteMasks[32][33];
|
|
|
|
|
|
|
|
|
|
// (1 << i) - 1
|
|
|
|
|
uint32 g_ExtraMasks[32];
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read/Write masks
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
class CBitWriteMasksInit
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
public:
|
2024-02-21 01:10:14 +01:00
|
|
|
|
CBitWriteMasksInit()
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
for (unsigned int startbit = 0; startbit < 32; startbit++)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned int nBitsLeft = 0; nBitsLeft < 33; nBitsLeft++)
|
|
|
|
|
{
|
|
|
|
|
unsigned int endbit = startbit + nBitsLeft;
|
2024-02-21 01:10:14 +01:00
|
|
|
|
g_BitWriteMasks[startbit][nBitsLeft] = GetBitForBitnum(startbit) - 1;
|
2023-04-10 15:02:56 +02:00
|
|
|
|
if (endbit < 32)
|
2024-02-21 01:10:14 +01:00
|
|
|
|
g_BitWriteMasks[startbit][nBitsLeft] |= ~(GetBitForBitnum(endbit) - 1);
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
for (unsigned int maskBit = 0; maskBit < 32; maskBit++)
|
2024-02-21 01:10:14 +01:00
|
|
|
|
g_ExtraMasks[maskBit] = GetBitForBitnum(maskBit) - 1;
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
2022-04-30 03:00:24 +02:00
|
|
|
|
};
|
2024-02-21 01:10:14 +01:00
|
|
|
|
static CBitWriteMasksInit s_BitWriteMasksInit;
|
|
|
|
|
|
|
|
|
|
const uint32 CBitBuffer::s_nMaskTable[33] = {
|
|
|
|
|
0,
|
|
|
|
|
(1 << 1) - 1,
|
|
|
|
|
(1 << 2) - 1,
|
|
|
|
|
(1 << 3) - 1,
|
|
|
|
|
(1 << 4) - 1,
|
|
|
|
|
(1 << 5) - 1,
|
|
|
|
|
(1 << 6) - 1,
|
|
|
|
|
(1 << 7) - 1,
|
|
|
|
|
(1 << 8) - 1,
|
|
|
|
|
(1 << 9) - 1,
|
|
|
|
|
(1 << 10) - 1,
|
|
|
|
|
(1 << 11) - 1,
|
|
|
|
|
(1 << 12) - 1,
|
|
|
|
|
(1 << 13) - 1,
|
|
|
|
|
(1 << 14) - 1,
|
|
|
|
|
(1 << 15) - 1,
|
|
|
|
|
(1 << 16) - 1,
|
|
|
|
|
(1 << 17) - 1,
|
|
|
|
|
(1 << 18) - 1,
|
|
|
|
|
(1 << 19) - 1,
|
|
|
|
|
(1 << 20) - 1,
|
|
|
|
|
(1 << 21) - 1,
|
|
|
|
|
(1 << 22) - 1,
|
|
|
|
|
(1 << 23) - 1,
|
|
|
|
|
(1 << 24) - 1,
|
|
|
|
|
(1 << 25) - 1,
|
|
|
|
|
(1 << 26) - 1,
|
|
|
|
|
(1 << 27) - 1,
|
|
|
|
|
(1 << 28) - 1,
|
|
|
|
|
(1 << 29) - 1,
|
|
|
|
|
(1 << 30) - 1,
|
|
|
|
|
0x7fffffff,
|
|
|
|
|
0xffffffff,
|
|
|
|
|
};
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Error handler
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
static BitBufErrorHandler g_BitBufErrorHandler = 0;
|
|
|
|
|
void InternalBitBufErrorHandler(BitBufErrorType errorType, const char* pDebugName)
|
|
|
|
|
{
|
|
|
|
|
if (g_BitBufErrorHandler)
|
|
|
|
|
g_BitBufErrorHandler(errorType, pDebugName);
|
|
|
|
|
}
|
|
|
|
|
void SetBitBufErrorHandler(BitBufErrorHandler fn)
|
|
|
|
|
{
|
|
|
|
|
g_BitBufErrorHandler = fn;
|
|
|
|
|
}
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
|
|
|
// CBitBuffer
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
2022-04-30 03:00:24 +02:00
|
|
|
|
CBitBuffer::CBitBuffer(void)
|
|
|
|
|
{
|
|
|
|
|
m_bOverflow = false;
|
|
|
|
|
m_pDebugName = NULL;
|
|
|
|
|
m_nDataBits = -1;
|
|
|
|
|
m_nDataBytes = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
|
|
|
// bf_read
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
2024-02-21 01:10:14 +01:00
|
|
|
|
CBitRead::CBitRead(const void* pData, size_t nBytes, ssize_t nBits /*= -1*/)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
StartReading(pData, nBytes, 0, nBits);
|
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
CBitRead::CBitRead(const char* pDebugName, const void* pData, size_t nBytes, ssize_t nBits /*= -1*/)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
SetDebugName(pDebugName);
|
|
|
|
|
StartReading(pData, nBytes, 0, nBits);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Core bf_read routines
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitRead::StartReading(const void* pData, size_t nBytes, ssize_t iStartBit, ssize_t nBits)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
// Make sure it's dword aligned and padded.
|
2024-02-21 01:10:14 +01:00
|
|
|
|
assert((ssize_t(pData) & 3) == 0);
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
m_pData = (uint32*)pData;
|
|
|
|
|
m_pDataIn = m_pData;
|
|
|
|
|
m_nDataBytes = nBytes;
|
|
|
|
|
|
|
|
|
|
if (nBits == -1)
|
|
|
|
|
{
|
|
|
|
|
m_nDataBits = nBytes << 3;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
assert(nBits <= (ssize_t)(nBytes * 8));
|
2023-04-10 15:02:56 +02:00
|
|
|
|
m_nDataBits = nBits;
|
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
m_bOverflow = false;
|
|
|
|
|
m_pBufferEnd = reinterpret_cast<uint32 const*> (reinterpret_cast<uint8 const*> (m_pData) + nBytes);
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
if (m_pData)
|
|
|
|
|
Seek(iStartBit);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// seeks to a specific position in the buffer
|
|
|
|
|
bool CBitRead::Seek(ssize_t nPosition)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
bool bSucc = true;
|
|
|
|
|
if (nPosition < 0 || nPosition > m_nDataBits)
|
|
|
|
|
{
|
|
|
|
|
SetOverflowFlag();
|
|
|
|
|
bSucc = false;
|
|
|
|
|
nPosition = m_nDataBits;
|
|
|
|
|
}
|
|
|
|
|
size_t nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off"
|
|
|
|
|
// at the head to make reading and detecting the end efficient.
|
|
|
|
|
|
|
|
|
|
size_t nByteOfs = nPosition / 8;
|
|
|
|
|
if ((m_nDataBytes < 4) || (nHead && (nByteOfs < nHead)))
|
|
|
|
|
{
|
|
|
|
|
// partial first dword
|
|
|
|
|
uint8 const* pPartial = (uint8 const*)m_pData;
|
|
|
|
|
if (m_pData)
|
|
|
|
|
{
|
|
|
|
|
m_nInBufWord = *(pPartial++);
|
|
|
|
|
if (nHead > 1)
|
|
|
|
|
m_nInBufWord |= (*pPartial++) << 8;
|
|
|
|
|
if (nHead > 2)
|
|
|
|
|
m_nInBufWord |= (*pPartial++) << 16;
|
|
|
|
|
}
|
|
|
|
|
m_pDataIn = (uint32 const*)pPartial;
|
|
|
|
|
m_nInBufWord >>= (nPosition & 31);
|
|
|
|
|
m_nBitsAvail = int((nHead << 3) - (nPosition & 31));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ssize_t nAdjPosition = nPosition - (nHead << 3);
|
|
|
|
|
m_pDataIn = reinterpret_cast<uint32 const*> (
|
|
|
|
|
reinterpret_cast<uint8 const*>(m_pData) + ((nAdjPosition / 32) << 2) + nHead);
|
|
|
|
|
if (m_pData)
|
|
|
|
|
{
|
|
|
|
|
m_nBitsAvail = 32;
|
|
|
|
|
GrabNextDWord();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_nInBufWord = 0;
|
|
|
|
|
m_nBitsAvail = 1;
|
|
|
|
|
}
|
|
|
|
|
m_nInBufWord >>= (nAdjPosition & 31);
|
2024-02-21 01:10:14 +01:00
|
|
|
|
m_nBitsAvail = MIN(m_nBitsAvail, 32 - (nAdjPosition & 31)); // in case grabnextdword overflowed
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
return bSucc;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for reading coordinates from the buffer (these contain bit-field
|
|
|
|
|
// size AND fixed point scaling constants)
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
float CBitRead::ReadBitCoord(void)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
int intval = 0, fractval = 0, signbit = 0;
|
|
|
|
|
float value = 0.0;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read the required integer and fraction flags
|
|
|
|
|
intval = ReadOneBit();
|
|
|
|
|
fractval = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// If we got either parse them, otherwise it's a zero.
|
|
|
|
|
if (intval || fractval)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read the sign bit
|
|
|
|
|
signbit = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// If there's an integer, read it in
|
|
|
|
|
if (intval)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
|
|
|
|
|
intval = ReadUBitLong(COORD_INTEGER_BITS) + 1;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
// If there's a fraction, read it in
|
|
|
|
|
if (fractval)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
fractval = ReadUBitLong(COORD_FRACTIONAL_BITS);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
// Calculate the correct floating point value
|
|
|
|
|
value = intval + (float)((float)fractval * COORD_RESOLUTION);
|
|
|
|
|
|
|
|
|
|
// Fixup the sign if negative.
|
|
|
|
|
if (signbit)
|
|
|
|
|
value = -value;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
return value;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
float CBitRead::ReadBitCoordMP(EBitCoordType coordType)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
bool bIntegral = (coordType == kCW_Integral);
|
|
|
|
|
bool bLowPrecision = (coordType == kCW_LowPrecision);
|
|
|
|
|
|
|
|
|
|
int intval = 0, fractval = 0, signbit = 0;
|
|
|
|
|
float value = 0.0;
|
|
|
|
|
|
|
|
|
|
bool bInBounds = ReadOneBit() ? true : false;
|
|
|
|
|
|
|
|
|
|
if (bIntegral)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read the required integer and fraction flags
|
|
|
|
|
intval = ReadOneBit();
|
|
|
|
|
// If we got either parse them, otherwise it's a zero.
|
|
|
|
|
if (intval)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read the sign bit
|
|
|
|
|
signbit = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// If there's an integer, read it in
|
|
|
|
|
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
|
|
|
|
|
if (bInBounds)
|
|
|
|
|
{
|
|
|
|
|
value = (float)ReadUBitLong(COORD_INTEGER_BITS_MP) + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
value = (float)ReadUBitLong(COORD_INTEGER_BITS) + 1;
|
|
|
|
|
}
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Read the required integer and fraction flags
|
|
|
|
|
intval = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// Read the sign bit
|
|
|
|
|
signbit = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// If we got either parse them, otherwise it's a zero.
|
|
|
|
|
if (intval)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
if (bInBounds)
|
|
|
|
|
{
|
|
|
|
|
intval = ReadUBitLong(COORD_INTEGER_BITS_MP) + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
intval = ReadUBitLong(COORD_INTEGER_BITS) + 1;
|
|
|
|
|
}
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
// If there's a fraction, read it in
|
|
|
|
|
fractval = ReadUBitLong(bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
|
|
|
|
|
|
|
|
|
|
// Calculate the correct floating point value
|
|
|
|
|
value = intval + ((float)fractval * (bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fixup the sign if negative.
|
|
|
|
|
if (signbit)
|
|
|
|
|
value = -value;
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
float CBitRead::ReadBitCellCoord(int bits, EBitCoordType coordType)
|
|
|
|
|
{
|
|
|
|
|
#if defined( BB_PROFILING )
|
|
|
|
|
VPROF("CBitRead::ReadBitCoordMP");
|
|
|
|
|
#endif
|
|
|
|
|
bool bIntegral = (coordType == kCW_Integral);
|
|
|
|
|
bool bLowPrecision = (coordType == kCW_LowPrecision);
|
|
|
|
|
|
|
|
|
|
int intval = 0, fractval = 0;
|
|
|
|
|
float value = 0.0;
|
|
|
|
|
|
|
|
|
|
if (bIntegral)
|
|
|
|
|
{
|
|
|
|
|
value = (float)ReadUBitLong(bits);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
intval = ReadUBitLong(bits);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// If there's a fraction, read it in
|
|
|
|
|
fractval = ReadUBitLong(bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Calculate the correct floating point value
|
|
|
|
|
value = intval + ((float)fractval * (bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION));
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
return value;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
float CBitRead::ReadBitNormal(void)
|
|
|
|
|
{
|
|
|
|
|
// Read the sign bit
|
|
|
|
|
int signbit = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
// Read the fractional part
|
|
|
|
|
unsigned int fractval = ReadUBitLong(NORMAL_FRACTIONAL_BITS);
|
|
|
|
|
|
|
|
|
|
// Calculate the correct floating point value
|
|
|
|
|
float value = (float)fractval * NORMAL_RESOLUTION;
|
|
|
|
|
|
|
|
|
|
// Fixup the sign if negative.
|
|
|
|
|
if (signbit)
|
|
|
|
|
value = -value;
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitRead::ReadBitVec3Coord(Vector3D& fa)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
int xflag, yflag, zflag;
|
|
|
|
|
|
|
|
|
|
// This vector must be initialized! Otherwise, If any of the flags aren't set,
|
|
|
|
|
// the corresponding component will not be read and will be stack garbage.
|
|
|
|
|
fa.Init(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
xflag = ReadOneBit();
|
|
|
|
|
yflag = ReadOneBit();
|
|
|
|
|
zflag = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
if (xflag)
|
|
|
|
|
fa[0] = ReadBitCoord();
|
|
|
|
|
if (yflag)
|
|
|
|
|
fa[1] = ReadBitCoord();
|
|
|
|
|
if (zflag)
|
|
|
|
|
fa[2] = ReadBitCoord();
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-21 11:28:55 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitRead::ReadBitVec3Normal(Vector3D& fa)
|
|
|
|
|
{
|
|
|
|
|
int xflag = ReadOneBit();
|
|
|
|
|
int yflag = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
if (xflag)
|
|
|
|
|
fa[0] = ReadBitNormal();
|
|
|
|
|
else
|
|
|
|
|
fa[0] = 0.0f;
|
|
|
|
|
|
|
|
|
|
if (yflag)
|
|
|
|
|
fa[1] = ReadBitNormal();
|
|
|
|
|
else
|
|
|
|
|
fa[1] = 0.0f;
|
|
|
|
|
|
|
|
|
|
// The first two imply the third (but not its sign)
|
|
|
|
|
int znegative = ReadOneBit();
|
|
|
|
|
|
|
|
|
|
float fafafbfb = fa[0] * fa[0] + fa[1] * fa[1];
|
|
|
|
|
if (fafafbfb < 1.0f)
|
|
|
|
|
fa[2] = sqrt(1.0f - fafafbfb);
|
|
|
|
|
else
|
|
|
|
|
fa[2] = 0.0f;
|
|
|
|
|
|
|
|
|
|
if (znegative)
|
|
|
|
|
fa[2] = -fa[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitRead::ReadBitAngles(QAngle& fa)
|
|
|
|
|
{
|
|
|
|
|
Vector3D tmp;
|
|
|
|
|
ReadBitVec3Coord(tmp);
|
|
|
|
|
fa.Init(tmp.x, tmp.y, tmp.z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
float CBitRead::ReadBitAngle(int numbits)
|
|
|
|
|
{
|
|
|
|
|
float shift = (float)(GetBitForBitnum(numbits));
|
|
|
|
|
|
|
|
|
|
int i = ReadUBitLong(numbits);
|
|
|
|
|
float fReturn = (float)i * (360.0f / shift);
|
|
|
|
|
|
|
|
|
|
return fReturn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for reading encoded (var)ints from the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-08-21 11:28:55 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int64 CBitRead::ReadLongLong()
|
|
|
|
|
{
|
|
|
|
|
int64 retval;
|
|
|
|
|
uint* pLongs = (uint*)&retval;
|
|
|
|
|
|
|
|
|
|
// Read the two DWORDs according to network endian
|
|
|
|
|
const short endianIndex = 0x0100;
|
|
|
|
|
byte* idx = (byte*)&endianIndex;
|
|
|
|
|
pLongs[*idx++] = ReadUBitLong(sizeof(long) << 3);
|
|
|
|
|
pLongs[*idx] = ReadUBitLong(sizeof(long) << 3);
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Read 1-5 bytes in order to extract a 32-bit unsigned value from the
|
|
|
|
|
// stream. 7 data bits are extracted from each byte with the 8th bit used
|
|
|
|
|
// to indicate whether the loop should continue.
|
|
|
|
|
// This allows variable size numbers to be stored with tolerable
|
|
|
|
|
// efficiency. Numbers sizes that can be stored for various numbers of
|
|
|
|
|
// encoded bits are:
|
|
|
|
|
// 8-bits: 0-127
|
|
|
|
|
// 16-bits: 128-16383
|
|
|
|
|
// 24-bits: 16384-2097151
|
|
|
|
|
// 32-bits: 2097152-268435455
|
|
|
|
|
// 40-bits: 268435456-0xFFFFFFFF
|
|
|
|
|
uint32 CBitRead::ReadVarInt32()
|
2023-08-21 11:28:55 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
uint32 result = 0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
uint32 b;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (count == bitbuf::kMaxVarint32Bytes)
|
|
|
|
|
{
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
b = ReadUBitLong(8);
|
|
|
|
|
result |= (b & 0x7F) << (7 * count);
|
|
|
|
|
++count;
|
|
|
|
|
} while (b & 0x80);
|
2023-08-21 11:28:55 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
return result;
|
2023-08-21 11:28:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
uint64 CBitRead::ReadVarInt64()
|
|
|
|
|
{
|
|
|
|
|
uint64 result = 0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
uint64 b;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (count == bitbuf::kMaxVarint64Bytes)
|
|
|
|
|
{
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
b = ReadUBitLong(8);
|
|
|
|
|
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
|
|
|
|
|
++count;
|
|
|
|
|
} while (b & 0x80);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for reading bits and bytes from the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-08-21 11:28:55 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitRead::ReadBits(void* pOutData, int nBits)
|
|
|
|
|
{
|
|
|
|
|
unsigned char* pOut = (unsigned char*)pOutData;
|
|
|
|
|
int nBitsLeft = nBits;
|
|
|
|
|
|
|
|
|
|
// align output to dword boundary
|
|
|
|
|
while (((uintp)pOut & 3) != 0 && nBitsLeft >= 8)
|
|
|
|
|
{
|
|
|
|
|
*pOut = (unsigned char)ReadUBitLong(8);
|
|
|
|
|
++pOut;
|
|
|
|
|
nBitsLeft -= 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// X360TBD: Can't read dwords in ReadBits because they'll get swapped
|
|
|
|
|
if (IsPC())
|
|
|
|
|
{
|
|
|
|
|
// read dwords
|
|
|
|
|
while (nBitsLeft >= 32)
|
|
|
|
|
{
|
|
|
|
|
*((uint32*)pOut) = ReadUBitLong(32);
|
|
|
|
|
pOut += sizeof(uint32);
|
|
|
|
|
nBitsLeft -= 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read remaining bytes
|
|
|
|
|
while (nBitsLeft >= 8)
|
|
|
|
|
{
|
|
|
|
|
*pOut = (unsigned char)ReadUBitLong(8);
|
|
|
|
|
++pOut;
|
|
|
|
|
nBitsLeft -= 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read remaining bits
|
|
|
|
|
if (nBitsLeft)
|
|
|
|
|
{
|
|
|
|
|
*pOut = (unsigned char)ReadUBitLong(nBitsLeft);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CBitRead::ReadBytes(void* pOut, int nBytes)
|
|
|
|
|
{
|
|
|
|
|
ReadBits(pOut, nBytes << 3);
|
|
|
|
|
return !IsOverflowed();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for reading encoded strings from the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-04-30 03:00:24 +02:00
|
|
|
|
bool CBitRead::ReadString(char* pStr, int maxLen, bool bLine, int* pOutNumChars)
|
|
|
|
|
{
|
|
|
|
|
assert(maxLen != 0);
|
|
|
|
|
|
|
|
|
|
bool bTooSmall = false;
|
|
|
|
|
int iChar = 0;
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2023-04-02 12:09:43 +02:00
|
|
|
|
char val = char(ReadChar());
|
2022-04-30 03:00:24 +02:00
|
|
|
|
if (val == 0)
|
|
|
|
|
break;
|
|
|
|
|
else if (bLine && val == '\n')
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (iChar < (maxLen - 1))
|
|
|
|
|
{
|
|
|
|
|
pStr[iChar] = val;
|
|
|
|
|
++iChar;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bTooSmall = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure it's null-terminated.
|
2023-04-09 23:35:58 +02:00
|
|
|
|
pStr[iChar] = '\0';
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
|
|
|
|
if (pOutNumChars)
|
|
|
|
|
*pOutNumChars = iChar;
|
|
|
|
|
|
|
|
|
|
return !IsOverflowed() && !bTooSmall;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CBitRead::ReadWString(OUT_Z_CAP(maxLenInChars) wchar_t* pStr, int maxLenInChars, bool bLine, int* pOutNumChars)
|
|
|
|
|
{
|
|
|
|
|
Assert(maxLenInChars != 0);
|
|
|
|
|
|
|
|
|
|
bool bTooSmall = false;
|
|
|
|
|
int iChar = 0;
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
wchar val = (wchar)ReadShort();
|
|
|
|
|
if (val == 0)
|
|
|
|
|
break;
|
|
|
|
|
else if (bLine && val == L'\n')
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (iChar < (maxLenInChars - 1))
|
|
|
|
|
{
|
|
|
|
|
pStr[iChar] = val;
|
|
|
|
|
++iChar;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bTooSmall = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure it's null-terminated.
|
|
|
|
|
Assert(iChar < maxLenInChars);
|
|
|
|
|
pStr[iChar] = 0;
|
|
|
|
|
|
|
|
|
|
if (pOutNumChars)
|
|
|
|
|
*pOutNumChars = iChar;
|
|
|
|
|
|
|
|
|
|
return !IsOverflowed() && !bTooSmall;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
char* CBitRead::ReadAndAllocateString(bool* pOverflow)
|
|
|
|
|
{
|
|
|
|
|
char str[2048];
|
|
|
|
|
|
|
|
|
|
int nChars;
|
|
|
|
|
bool bOverflow = !ReadString(str, sizeof(str), false, &nChars);
|
|
|
|
|
if (pOverflow)
|
|
|
|
|
*pOverflow = bOverflow;
|
|
|
|
|
|
|
|
|
|
// Now copy into the output and return it;
|
|
|
|
|
char* pRet = new char[nChars + 1];
|
|
|
|
|
for (int i = 0; i <= nChars; i++)
|
|
|
|
|
pRet[i] = str[i];
|
|
|
|
|
|
|
|
|
|
return pRet;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
|
|
|
// bf_write
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
2023-08-21 11:35:24 +02:00
|
|
|
|
CBitWrite::CBitWrite()
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//DEBUG_LINK_CHECK;
|
|
|
|
|
m_pData = NULL;
|
|
|
|
|
m_nDataBytes = 0;
|
|
|
|
|
m_nDataBits = -1; // set to -1 so we generate overflow on any operation
|
|
|
|
|
m_iCurBit = 0;
|
|
|
|
|
m_bOverflow = false;
|
|
|
|
|
m_bAssertOnOverflow = true;
|
|
|
|
|
m_pDebugName = NULL;
|
|
|
|
|
}
|
2023-08-21 11:35:24 +02:00
|
|
|
|
CBitWrite::CBitWrite(const char* pDebugName, void* pData, int nBytes, int nBits)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
//DEBUG_LINK_CHECK;
|
|
|
|
|
m_bAssertOnOverflow = true;
|
|
|
|
|
m_pDebugName = pDebugName;
|
|
|
|
|
StartWriting(pData, nBytes, 0, nBits);
|
|
|
|
|
}
|
2023-08-21 11:35:24 +02:00
|
|
|
|
CBitWrite::CBitWrite(void* pData, int nBytes, int nBits)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
m_bAssertOnOverflow = true;
|
|
|
|
|
m_pDebugName = NULL;
|
|
|
|
|
StartWriting(pData, nBytes, 0, nBits);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Core bf_write routines
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-08-21 11:35:24 +02:00
|
|
|
|
void CBitWrite::StartWriting(void* pData, int nBytes, int iStartBit, int nBits)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
// Make sure it's dword aligned and padded.
|
|
|
|
|
//DEBUG_LINK_CHECK;
|
|
|
|
|
Assert((nBytes % 4) == 0);
|
|
|
|
|
Assert(((uintp)pData & 3) == 0);
|
|
|
|
|
|
|
|
|
|
// The writing code will overrun the end of the buffer if it isn't dword aligned, so truncate to force alignment
|
|
|
|
|
nBytes &= ~3;
|
|
|
|
|
|
|
|
|
|
m_pData = (unsigned char*)pData;
|
|
|
|
|
m_nDataBytes = nBytes;
|
|
|
|
|
|
|
|
|
|
if (nBits == -1)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
m_nDataBits = nBytes << 3;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Assert(nBits <= nBytes * 8);
|
|
|
|
|
m_nDataBits = nBits;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
m_iCurBit = iStartBit;
|
|
|
|
|
m_bOverflow = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// checks if we have enough space for the requested number of bits
|
|
|
|
|
bool CBitWrite::CheckForOverflow(int nBits)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
if (this->m_iCurBit + nBits > this->m_nDataBits)
|
|
|
|
|
{
|
|
|
|
|
this->SetOverflowFlag();
|
|
|
|
|
}
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
return IsOverflowed();
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// sets the overflow flag
|
|
|
|
|
void CBitWrite::SetOverflowFlag()
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
if (this->m_bAssertOnOverflow)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
assert(false);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
this->m_bOverflow = true;
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for writing integers into the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// writes an unsigned integer into the buffer
|
|
|
|
|
void CBitWrite::WriteUBitLong(unsigned int curData, int numbits, bool bCheckRange)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
// Make sure it doesn't overflow.
|
|
|
|
|
if (bCheckRange && numbits < 32)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
if (curData >= (uint32)(1 << numbits))
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
CallErrorHandler(BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName());
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-10 15:02:56 +02:00
|
|
|
|
Assert(numbits >= 0 && numbits <= 32);
|
2023-04-10 23:45:09 +02:00
|
|
|
|
#else
|
|
|
|
|
NOTE_UNUSED(bCheckRange);
|
2023-04-10 15:02:56 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Bounds checking..
|
|
|
|
|
if ((m_iCurBit + numbits) > m_nDataBits)
|
|
|
|
|
{
|
|
|
|
|
m_iCurBit = m_nDataBits;
|
|
|
|
|
SetOverflowFlag();
|
|
|
|
|
CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nBitsLeft = numbits;
|
|
|
|
|
int iCurBit = m_iCurBit;
|
|
|
|
|
|
|
|
|
|
// Mask in a dword.
|
|
|
|
|
unsigned int iDWord = iCurBit >> 5;
|
|
|
|
|
Assert((iDWord * 4 + sizeof(int32)) <= (unsigned int)m_nDataBytes);
|
|
|
|
|
|
|
|
|
|
uint32 iCurBitMasked = iCurBit & 31;
|
|
|
|
|
|
|
|
|
|
uint32 dword = LoadLittleDWord((uint32*)m_pData, iDWord);
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
dword &= g_BitWriteMasks[iCurBitMasked][nBitsLeft];
|
2023-04-10 15:02:56 +02:00
|
|
|
|
dword |= curData << iCurBitMasked;
|
|
|
|
|
|
|
|
|
|
// write to stream (lsb to msb) properly
|
|
|
|
|
StoreLittleDWord((uint32*)m_pData, iDWord, dword);
|
|
|
|
|
|
|
|
|
|
// Did it span a dword?
|
|
|
|
|
int nBitsWritten = 32 - iCurBitMasked;
|
|
|
|
|
if (nBitsWritten < nBitsLeft)
|
|
|
|
|
{
|
|
|
|
|
nBitsLeft -= nBitsWritten;
|
|
|
|
|
curData >>= nBitsWritten;
|
|
|
|
|
|
|
|
|
|
// read from stream (lsb to msb) properly
|
|
|
|
|
dword = LoadLittleDWord((uint32*)m_pData, iDWord + 1);
|
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
dword &= g_BitWriteMasks[0][nBitsLeft];
|
2023-04-10 15:02:56 +02:00
|
|
|
|
dword |= curData;
|
|
|
|
|
|
|
|
|
|
// write to stream (lsb to msb) properly
|
|
|
|
|
StoreLittleDWord((uint32*)m_pData, iDWord + 1, dword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_iCurBit += numbits;
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// NOTE: Sign bit comes first
|
2023-08-21 11:35:24 +02:00
|
|
|
|
void CBitWrite::WriteSBitLong(int data, int numbits)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// Do we have a valid # of bits to encode with?
|
|
|
|
|
Assert(numbits >= 1);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
|
2023-04-18 20:14:20 +02:00
|
|
|
|
// Note: it does this weirdness here so it's bit-compatible with regular integer data in the buffer.
|
2023-04-10 15:02:56 +02:00
|
|
|
|
// (Some old code writes direct integers right into the buffer).
|
|
|
|
|
if (data < 0)
|
2022-04-30 03:00:24 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
if (numbits < 32)
|
|
|
|
|
{
|
|
|
|
|
// Make sure it doesn't overflow.
|
|
|
|
|
|
|
|
|
|
if (data < 0)
|
|
|
|
|
{
|
2023-04-10 22:31:42 +02:00
|
|
|
|
Assert(data >= -(GetBitForBitnum(numbits - 1)));
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-04-10 22:31:42 +02:00
|
|
|
|
Assert(data < (GetBitForBitnum(numbits - 1)));
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
WriteUBitLong((unsigned int)(0x80000000 + data), numbits - 1, false);
|
|
|
|
|
WriteOneBit(1);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
WriteUBitLong((unsigned int)data, numbits - 1);
|
|
|
|
|
WriteOneBit(0);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-08-21 11:35:24 +02:00
|
|
|
|
void CBitWrite::WriteBitLong(unsigned int data, int numbits, bool bSigned)
|
2023-04-10 15:02:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (bSigned)
|
|
|
|
|
WriteSBitLong((int)data, numbits);
|
|
|
|
|
else
|
|
|
|
|
WriteUBitLong(data, numbits);
|
2022-04-30 03:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-08-21 11:35:24 +02:00
|
|
|
|
bool CBitWrite::WriteBits(const void* pInData, int nBits)
|
2022-04-02 02:48:54 +02:00
|
|
|
|
{
|
2023-04-10 15:02:56 +02:00
|
|
|
|
unsigned char* pIn = (unsigned char*)pInData;
|
|
|
|
|
int nBitsLeft = nBits;
|
|
|
|
|
|
|
|
|
|
// Bounds checking..
|
|
|
|
|
if ((m_iCurBit + nBits) > m_nDataBits)
|
|
|
|
|
{
|
|
|
|
|
SetOverflowFlag();
|
|
|
|
|
CallErrorHandler(BITBUFERROR_BUFFER_OVERRUN, GetDebugName());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Align input to dword boundary
|
|
|
|
|
while (((uintp)pIn & 3) != 0 && nBitsLeft >= 8)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(*pIn, 8, false);
|
|
|
|
|
++pIn;
|
|
|
|
|
nBitsLeft -= 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nBitsLeft >= 32)
|
|
|
|
|
{
|
|
|
|
|
if ((m_iCurBit & 7) == 0)
|
|
|
|
|
{
|
|
|
|
|
// current bit is byte aligned, do block copy
|
|
|
|
|
int numbytes = nBitsLeft >> 3;
|
|
|
|
|
int numbits = numbytes << 3;
|
|
|
|
|
|
|
|
|
|
memcpy(m_pData + (m_iCurBit >> 3), pIn, numbytes);
|
|
|
|
|
pIn += numbytes;
|
|
|
|
|
nBitsLeft -= numbits;
|
|
|
|
|
m_iCurBit += numbits;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const uint32 iBitsRight = (m_iCurBit & 31);
|
|
|
|
|
Assert(iBitsRight > 0); // should not be aligned, otherwise it would have been handled before
|
|
|
|
|
const uint32 iBitsLeft = 32 - iBitsRight;
|
|
|
|
|
const int iBitsChanging = 32 + iBitsLeft; // how many bits are changed during one step (not necessary written meaningful)
|
|
|
|
|
unsigned int iDWord = m_iCurBit >> 5;
|
|
|
|
|
|
|
|
|
|
uint32 outWord = LoadLittleDWord((uint32*)m_pData, iDWord);
|
2024-02-21 01:10:14 +01:00
|
|
|
|
outWord &= g_BitWriteMasks[iBitsRight][32]; // clear rest of beginning DWORD
|
2023-04-10 15:02:56 +02:00
|
|
|
|
|
|
|
|
|
// copy in DWORD blocks
|
|
|
|
|
while (nBitsLeft >= iBitsChanging)
|
|
|
|
|
{
|
|
|
|
|
uint32 curData = LittleDWord(*(uint32*)pIn);
|
|
|
|
|
pIn += sizeof(uint32);
|
|
|
|
|
|
|
|
|
|
outWord |= curData << iBitsRight;
|
|
|
|
|
StoreLittleDWord((uint32*)m_pData, iDWord, outWord);
|
|
|
|
|
|
|
|
|
|
++iDWord;
|
|
|
|
|
outWord = curData >> iBitsLeft;
|
|
|
|
|
|
|
|
|
|
nBitsLeft -= 32;
|
|
|
|
|
m_iCurBit += 32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// store last word
|
|
|
|
|
StoreLittleDWord((uint32*)m_pData, iDWord, outWord);
|
|
|
|
|
|
|
|
|
|
// write remaining DWORD
|
|
|
|
|
if (nBitsLeft >= 32)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(LittleDWord(*((uint32*)pIn)), 32, false);
|
|
|
|
|
pIn += sizeof(uint32);
|
|
|
|
|
nBitsLeft -= 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write remaining bytes
|
|
|
|
|
while (nBitsLeft >= 8)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(*pIn, 8, false);
|
|
|
|
|
++pIn;
|
|
|
|
|
nBitsLeft -= 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write remaining bits
|
|
|
|
|
if (nBitsLeft)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(*pIn, nBitsLeft, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !IsOverflowed();
|
2022-04-02 02:48:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
bool CBitWrite::WriteBitsFromBuffer(bf_read* pIn, int nBits)
|
|
|
|
|
{
|
|
|
|
|
// This could be optimized a little by
|
|
|
|
|
while (nBits > 32)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(pIn->ReadUBitLong(32), 32);
|
|
|
|
|
nBits -= 32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteUBitLong(pIn->ReadUBitLong(nBits), nBits);
|
|
|
|
|
return !IsOverflowed() && !pIn->IsOverflowed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for writing integers with variable bit length into the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitWrite::WriteVarInt32(uint32 data)
|
2022-04-02 02:48:54 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Check if align and we have room, slow path if not
|
|
|
|
|
if ((m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarint32Bytes * 8) <= m_nDataBits)
|
2022-04-02 02:48:54 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
uint8* target = ((uint8*)m_pData) + (m_iCurBit >> 3);
|
|
|
|
|
|
|
|
|
|
target[0] = static_cast<uint8>(data | 0x80);
|
|
|
|
|
if (data >= (1 << 7))
|
|
|
|
|
{
|
|
|
|
|
target[1] = static_cast<uint8>((data >> 7) | 0x80);
|
|
|
|
|
if (data >= (1 << 14))
|
|
|
|
|
{
|
|
|
|
|
target[2] = static_cast<uint8>((data >> 14) | 0x80);
|
|
|
|
|
if (data >= (1 << 21))
|
|
|
|
|
{
|
|
|
|
|
target[3] = static_cast<uint8>((data >> 21) | 0x80);
|
|
|
|
|
if (data >= (1 << 28))
|
|
|
|
|
{
|
|
|
|
|
target[4] = static_cast<uint8>(data >> 28);
|
|
|
|
|
m_iCurBit += 5 * 8;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
target[3] &= 0x7F;
|
|
|
|
|
m_iCurBit += 4 * 8;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
target[2] &= 0x7F;
|
|
|
|
|
m_iCurBit += 3 * 8;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
target[1] &= 0x7F;
|
|
|
|
|
m_iCurBit += 2 * 8;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
target[0] &= 0x7F;
|
|
|
|
|
m_iCurBit += 1 * 8;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
else // Slow path
|
|
|
|
|
{
|
|
|
|
|
while (data > 0x7F)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong((data & 0x7F) | 0x80, 8);
|
|
|
|
|
data >>= 7;
|
|
|
|
|
}
|
|
|
|
|
WriteUBitLong(data & 0x7F, 8);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteVarInt64(uint64 data)
|
|
|
|
|
{
|
|
|
|
|
// Check if align and we have room, slow path if not
|
|
|
|
|
if ((m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarint64Bytes * 8) <= m_nDataBits)
|
|
|
|
|
{
|
|
|
|
|
uint8* target = ((uint8*)m_pData) + (m_iCurBit >> 3);
|
|
|
|
|
|
|
|
|
|
// Splitting into 32-bit pieces gives better performance on 32-bit
|
|
|
|
|
// processors.
|
|
|
|
|
uint32 part0 = static_cast<uint32>(data);
|
|
|
|
|
uint32 part1 = static_cast<uint32>(data >> 28);
|
|
|
|
|
uint32 part2 = static_cast<uint32>(data >> 56);
|
|
|
|
|
|
|
|
|
|
int size;
|
|
|
|
|
|
|
|
|
|
// Here we can't really optimize for small numbers, since the data is
|
|
|
|
|
// split into three parts. Cheking for numbers < 128, for instance,
|
|
|
|
|
// would require three comparisons, since you'd have to make sure part1
|
|
|
|
|
// and part2 are zero. However, if the caller is using 64-bit integers,
|
|
|
|
|
// it is likely that they expect the numbers to often be very large, so
|
|
|
|
|
// we probably don't want to optimize for small numbers anyway. Thus,
|
|
|
|
|
// we end up with a hardcoded binary search tree...
|
|
|
|
|
if (part2 == 0)
|
|
|
|
|
{
|
|
|
|
|
if (part1 == 0)
|
|
|
|
|
{
|
|
|
|
|
if (part0 < (1 << 14))
|
|
|
|
|
{
|
|
|
|
|
if (part0 < (1 << 7))
|
|
|
|
|
{
|
|
|
|
|
size = 1; goto size1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = 2; goto size2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (part0 < (1 << 21))
|
|
|
|
|
{
|
|
|
|
|
size = 3; goto size3;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = 4; goto size4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (part1 < (1 << 14))
|
|
|
|
|
{
|
|
|
|
|
if (part1 < (1 << 7))
|
|
|
|
|
{
|
|
|
|
|
size = 5; goto size5;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = 6; goto size6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (part1 < (1 << 21))
|
|
|
|
|
{
|
|
|
|
|
size = 7; goto size7;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = 8; goto size8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (part2 < (1 << 7))
|
|
|
|
|
{
|
|
|
|
|
size = 9; goto size9;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = 10; goto size10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// commented as this would otherwise trigger a compiled warning in MSVC
|
|
|
|
|
// which confirms this code is unreachable
|
|
|
|
|
//AssertFatalMsg(false, "Can't get here.");
|
|
|
|
|
|
|
|
|
|
size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
|
|
|
|
|
size9: target[8] = static_cast<uint8>((part2) | 0x80);
|
|
|
|
|
size8: target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
|
|
|
|
|
size7: target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
|
|
|
|
|
size6: target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
|
|
|
|
|
size5: target[4] = static_cast<uint8>((part1) | 0x80);
|
|
|
|
|
size4: target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
|
|
|
|
|
size3: target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
|
|
|
|
|
size2: target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
|
|
|
|
|
size1: target[0] = static_cast<uint8>((part0) | 0x80);
|
|
|
|
|
|
|
|
|
|
target[size - 1] &= 0x7F;
|
|
|
|
|
m_iCurBit += size * 8;
|
|
|
|
|
}
|
|
|
|
|
else // slow path
|
|
|
|
|
{
|
|
|
|
|
while (data > 0x7F)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong((data & 0x7F) | 0x80, 8);
|
|
|
|
|
data >>= 7;
|
|
|
|
|
}
|
|
|
|
|
WriteUBitLong(data & 0x7F, 8);
|
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitWrite::WriteSignedVarInt32(int32 data)
|
|
|
|
|
{
|
|
|
|
|
WriteVarInt32(bitbuf::ZigZagEncode32(data));
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 15:02:56 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-21 01:10:14 +01:00
|
|
|
|
void CBitWrite::WriteSignedVarInt64(int64 data)
|
2022-04-02 02:48:54 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
WriteVarInt64(bitbuf::ZigZagEncode64(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int CBitWrite::ByteSizeVarInt32(uint32 data)
|
|
|
|
|
{
|
|
|
|
|
int size = 1;
|
|
|
|
|
while (data > 0x7F) {
|
|
|
|
|
size++;
|
|
|
|
|
data >>= 7;
|
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int CBitWrite::ByteSizeVarInt64(uint64 data)
|
|
|
|
|
{
|
|
|
|
|
int size = 1;
|
|
|
|
|
while (data > 0x7F) {
|
|
|
|
|
size++;
|
|
|
|
|
data >>= 7;
|
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int CBitWrite::ByteSizeSignedVarInt32(int32 data)
|
|
|
|
|
{
|
|
|
|
|
return ByteSizeVarInt32(bitbuf::ZigZagEncode32(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int CBitWrite::ByteSizeSignedVarInt64(int64 data)
|
|
|
|
|
{
|
|
|
|
|
return ByteSizeVarInt64(bitbuf::ZigZagEncode64(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for writing coordinates into the buffer (these contain bit-field
|
|
|
|
|
// size AND fixed point scaling constants)
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitAngle(float fAngle, int numbits)
|
|
|
|
|
{
|
|
|
|
|
int d;
|
|
|
|
|
unsigned int mask;
|
|
|
|
|
unsigned int shift;
|
|
|
|
|
|
|
|
|
|
shift = GetBitForBitnum(numbits);
|
|
|
|
|
mask = shift - 1;
|
|
|
|
|
|
|
|
|
|
d = (int)((fAngle / 360.0) * shift);
|
|
|
|
|
d &= mask;
|
|
|
|
|
|
|
|
|
|
WriteUBitLong((unsigned int)d, numbits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitCoord(const float f)
|
|
|
|
|
{
|
|
|
|
|
#if defined( BB_PROFILING )
|
|
|
|
|
VPROF("CBitWrite::WriteBitCoord");
|
|
|
|
|
#endif
|
|
|
|
|
int signbit = (f <= -COORD_RESOLUTION);
|
|
|
|
|
int intval = (int)abs(f);
|
|
|
|
|
int fractval = abs((int)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1);
|
|
|
|
|
|
|
|
|
|
// Send the bit flags that indicate whether we have an integer part and/or a fraction part.
|
|
|
|
|
WriteOneBit(intval);
|
|
|
|
|
WriteOneBit(fractval);
|
|
|
|
|
|
|
|
|
|
if (intval || fractval)
|
2022-04-02 02:48:54 +02:00
|
|
|
|
{
|
2024-02-21 01:10:14 +01:00
|
|
|
|
// Send the sign bit
|
|
|
|
|
WriteOneBit(signbit);
|
|
|
|
|
|
|
|
|
|
// Send the integer if we have one.
|
|
|
|
|
if (intval)
|
|
|
|
|
{
|
|
|
|
|
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
|
|
|
|
|
intval--;
|
|
|
|
|
WriteUBitLong((unsigned int)intval, COORD_INTEGER_BITS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send the fraction if we have one
|
|
|
|
|
if (fractval)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong((unsigned int)fractval, COORD_FRACTIONAL_BITS);
|
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
}
|
2024-02-21 01:10:14 +01:00
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
|
2024-02-21 01:10:14 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitCoordMP(const float f, bool bIntegral, bool bLowPrecision)
|
|
|
|
|
{
|
|
|
|
|
#if defined( BB_PROFILING )
|
|
|
|
|
VPROF("CBitWrite::WriteBitCoordMP");
|
|
|
|
|
#endif
|
|
|
|
|
int signbit = (f <= -(bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION));
|
|
|
|
|
int intval = (int)abs(f);
|
|
|
|
|
int fractval = bLowPrecision ?
|
|
|
|
|
(abs((int)(f * COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION - 1)) :
|
|
|
|
|
(abs((int)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1));
|
|
|
|
|
|
|
|
|
|
bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP);
|
|
|
|
|
|
|
|
|
|
unsigned int bits, numbits;
|
|
|
|
|
|
|
|
|
|
if (bIntegral)
|
|
|
|
|
{
|
|
|
|
|
// Integer encoding: in-bounds bit, nonzero bit, optional sign bit + integer value bits
|
|
|
|
|
if (intval)
|
|
|
|
|
{
|
|
|
|
|
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
|
|
|
|
|
--intval;
|
|
|
|
|
bits = intval * 8 + signbit * 4 + 2 + bInBounds;
|
|
|
|
|
numbits = 3 + (bInBounds ? COORD_INTEGER_BITS_MP : COORD_INTEGER_BITS);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bits = bInBounds;
|
|
|
|
|
numbits = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Float encoding: in-bounds bit, integer bit, sign bit, fraction value bits, optional integer value bits
|
|
|
|
|
if (intval)
|
|
|
|
|
{
|
|
|
|
|
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
|
|
|
|
|
--intval;
|
|
|
|
|
bits = intval * 8 + signbit * 4 + 2 + bInBounds;
|
|
|
|
|
bits += bInBounds ? (fractval << (3 + COORD_INTEGER_BITS_MP)) : (fractval << (3 + COORD_INTEGER_BITS));
|
|
|
|
|
numbits = 3 + (bInBounds ? COORD_INTEGER_BITS_MP : COORD_INTEGER_BITS)
|
|
|
|
|
+ (bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bits = fractval * 8 + signbit * 4 + 0 + bInBounds;
|
|
|
|
|
numbits = 3 + (bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteUBitLong(bits, numbits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitCellCoord(const float f, int bits, EBitCoordType coordType)
|
|
|
|
|
{
|
|
|
|
|
#if defined( BB_PROFILING )
|
|
|
|
|
VPROF("CBitWrite::WriteBitCellCoord");
|
|
|
|
|
#endif
|
|
|
|
|
Assert(f >= 0.0f); // cell coords can't be negative
|
|
|
|
|
Assert(f < (1 << bits));
|
|
|
|
|
|
|
|
|
|
bool bIntegral = (coordType == kCW_Integral);
|
|
|
|
|
bool bLowPrecision = (coordType == kCW_LowPrecision);
|
|
|
|
|
|
|
|
|
|
int intval = (int)abs(f);
|
|
|
|
|
int fractval = bLowPrecision ?
|
|
|
|
|
(abs((int)(f * COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION - 1)) :
|
|
|
|
|
(abs((int)(f * COORD_DENOMINATOR)) & (COORD_DENOMINATOR - 1));
|
|
|
|
|
|
|
|
|
|
if (bIntegral)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong((unsigned int)intval, bits);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong((unsigned int)intval, bits);
|
|
|
|
|
WriteUBitLong((unsigned int)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitVec3Coord(const Vector3D& fa)
|
|
|
|
|
{
|
|
|
|
|
int xflag, yflag, zflag;
|
|
|
|
|
|
|
|
|
|
xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION);
|
|
|
|
|
yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION);
|
|
|
|
|
zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION);
|
|
|
|
|
|
|
|
|
|
WriteOneBit(xflag);
|
|
|
|
|
WriteOneBit(yflag);
|
|
|
|
|
WriteOneBit(zflag);
|
|
|
|
|
|
|
|
|
|
if (xflag)
|
|
|
|
|
WriteBitCoord(fa[0]);
|
|
|
|
|
if (yflag)
|
|
|
|
|
WriteBitCoord(fa[1]);
|
|
|
|
|
if (zflag)
|
|
|
|
|
WriteBitCoord(fa[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitNormal(float f)
|
|
|
|
|
{
|
|
|
|
|
int signbit = (f <= -NORMAL_RESOLUTION);
|
|
|
|
|
|
|
|
|
|
// NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones
|
|
|
|
|
unsigned int fractval = abs((int)(f * NORMAL_DENOMINATOR));
|
|
|
|
|
|
|
|
|
|
// clamp..
|
|
|
|
|
if (fractval > NORMAL_DENOMINATOR)
|
|
|
|
|
fractval = NORMAL_DENOMINATOR;
|
|
|
|
|
|
|
|
|
|
// Send the sign bit
|
|
|
|
|
WriteOneBit(signbit);
|
|
|
|
|
|
|
|
|
|
// Send the fractional component
|
|
|
|
|
WriteUBitLong(fractval, NORMAL_FRACTIONAL_BITS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitVec3Normal(const Vector3D& fa)
|
|
|
|
|
{
|
|
|
|
|
int xflag, yflag;
|
|
|
|
|
|
|
|
|
|
xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION);
|
|
|
|
|
yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION);
|
|
|
|
|
|
|
|
|
|
WriteOneBit(xflag);
|
|
|
|
|
WriteOneBit(yflag);
|
|
|
|
|
|
|
|
|
|
if (xflag)
|
|
|
|
|
WriteBitNormal(fa[0]);
|
|
|
|
|
if (yflag)
|
|
|
|
|
WriteBitNormal(fa[1]);
|
|
|
|
|
|
|
|
|
|
// Write z sign bit
|
|
|
|
|
int signbit = (fa[2] <= -NORMAL_RESOLUTION);
|
|
|
|
|
WriteOneBit(signbit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteBitAngles(const QAngle& fa)
|
|
|
|
|
{
|
|
|
|
|
// FIXME:
|
|
|
|
|
Vector3D tmp(fa.x, fa.y, fa.z);
|
|
|
|
|
WriteBitVec3Coord(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for writing basic integral types into the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteChar(int val)
|
|
|
|
|
{
|
|
|
|
|
WriteSBitLong(val, sizeof(char) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteByte(int val)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(val, sizeof(unsigned char) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteShort(int val)
|
|
|
|
|
{
|
|
|
|
|
WriteSBitLong(val, sizeof(short) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteWord(int val)
|
|
|
|
|
{
|
|
|
|
|
WriteUBitLong(val, sizeof(unsigned short) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteLong(long val)
|
|
|
|
|
{
|
|
|
|
|
WriteSBitLong(val, sizeof(long) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteLongLong(int64 val)
|
|
|
|
|
{
|
|
|
|
|
uint* pLongs = (uint*)&val;
|
|
|
|
|
|
|
|
|
|
// Insert the two DWORDS according to network endian
|
|
|
|
|
const short endianIndex = 0x0100;
|
|
|
|
|
byte* idx = (byte*)&endianIndex;
|
|
|
|
|
WriteUBitLong(pLongs[*idx++], sizeof(long) << 3);
|
|
|
|
|
WriteUBitLong(pLongs[*idx], sizeof(long) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CBitWrite::WriteFloat(float val)
|
|
|
|
|
{
|
|
|
|
|
// Pre-swap the float, since WriteBits writes raw data
|
|
|
|
|
LittleFloat(&val, &val);
|
|
|
|
|
|
|
|
|
|
WriteBits(&val, sizeof(val) << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CBitWrite::WriteBytes(const void* pBuf, int nBytes)
|
|
|
|
|
{
|
|
|
|
|
return WriteBits(pBuf, nBytes << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Routines for writing strings into the buffer
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CBitWrite::WriteString(const char* pStr)
|
|
|
|
|
{
|
|
|
|
|
if (pStr)
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
WriteChar(*pStr);
|
|
|
|
|
++pStr;
|
|
|
|
|
} while (*(pStr - 1) != 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WriteChar(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !IsOverflowed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CBitWrite::WriteWString(const wchar_t* pStr)
|
|
|
|
|
{
|
|
|
|
|
if (pStr)
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
WriteShort(*pStr);
|
|
|
|
|
++pStr;
|
|
|
|
|
} while (*(pStr - 1) != 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WriteShort(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !IsOverflowed();
|
2023-04-10 15:02:56 +02:00
|
|
|
|
}
|