You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1626 lines
33 KiB
1626 lines
33 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "bitbuf.h"
|
|
#include "coordsize.h"
|
|
#include "mathlib/vector.h"
|
|
#include "mathlib/mathlib.h"
|
|
#include "tier1/strtools.h"
|
|
#include "bitvec.h"
|
|
|
|
// FIXME: Can't use this until we get multithreaded allocations in tier0 working for tools
|
|
// This is used by VVIS and fails to link
|
|
// NOTE: This must be the last file included!!!
|
|
//#include "tier0/memdbgon.h"
|
|
|
|
#ifdef _X360
|
|
// mandatory ... wary of above comment and isolating, tier0 is built as MT though
|
|
#include "tier0/memdbgon.h"
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
static volatile char const *pDebugString;
|
|
#define DEBUG_LINK_CHECK pDebugString = "tier1.lib built debug!"
|
|
#else
|
|
#define DEBUG_LINK_CHECK
|
|
#endif
|
|
|
|
#if _WIN32
|
|
#define FAST_BIT_SCAN 1
|
|
#if defined( _X360 )
|
|
#define CountLeadingZeros(x) _CountLeadingZeros(x)
|
|
inline unsigned int CountTrailingZeros( unsigned int elem )
|
|
{
|
|
// this implements CountTrailingZeros() / BitScanForward()
|
|
unsigned int mask = elem-1;
|
|
unsigned int comp = ~elem;
|
|
elem = mask & comp;
|
|
return (32 - _CountLeadingZeros(elem));
|
|
}
|
|
#else
|
|
#include <intrin.h>
|
|
#pragma intrinsic(_BitScanReverse)
|
|
#pragma intrinsic(_BitScanForward)
|
|
|
|
inline unsigned int CountLeadingZeros(unsigned int x)
|
|
{
|
|
unsigned long firstBit;
|
|
if ( _BitScanReverse(&firstBit,x) )
|
|
return 31 - firstBit;
|
|
return 32;
|
|
}
|
|
inline unsigned int CountTrailingZeros(unsigned int elem)
|
|
{
|
|
unsigned long out;
|
|
if ( _BitScanForward(&out, elem) )
|
|
return out;
|
|
return 32;
|
|
}
|
|
|
|
#endif
|
|
#else
|
|
#define FAST_BIT_SCAN 0
|
|
#endif
|
|
|
|
|
|
static BitBufErrorHandler g_BitBufErrorHandler = 0;
|
|
|
|
inline int BitForBitnum(int bitnum)
|
|
{
|
|
return GetBitForBitnum(bitnum);
|
|
}
|
|
|
|
void InternalBitBufErrorHandler( BitBufErrorType errorType, const char *pDebugName )
|
|
{
|
|
if ( g_BitBufErrorHandler )
|
|
g_BitBufErrorHandler( errorType, pDebugName );
|
|
}
|
|
|
|
|
|
void SetBitBufErrorHandler( BitBufErrorHandler fn )
|
|
{
|
|
g_BitBufErrorHandler = fn;
|
|
}
|
|
|
|
|
|
// #define BB_PROFILING
|
|
|
|
|
|
// 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];
|
|
|
|
class CBitWriteMasksInit
|
|
{
|
|
public:
|
|
CBitWriteMasksInit()
|
|
{
|
|
for( unsigned int startbit=0; startbit < 32; startbit++ )
|
|
{
|
|
for( unsigned int nBitsLeft=0; nBitsLeft < 33; nBitsLeft++ )
|
|
{
|
|
unsigned int endbit = startbit + nBitsLeft;
|
|
g_BitWriteMasks[startbit][nBitsLeft] = BitForBitnum(startbit) - 1;
|
|
if(endbit < 32)
|
|
g_BitWriteMasks[startbit][nBitsLeft] |= ~(BitForBitnum(endbit) - 1);
|
|
}
|
|
}
|
|
|
|
for ( unsigned int maskBit=0; maskBit < 32; maskBit++ )
|
|
g_ExtraMasks[maskBit] = BitForBitnum(maskBit) - 1;
|
|
}
|
|
};
|
|
CBitWriteMasksInit g_BitWriteMasksInit;
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
// bf_write
|
|
// ---------------------------------------------------------------------------------------- //
|
|
|
|
bf_write::bf_write()
|
|
{
|
|
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;
|
|
}
|
|
|
|
bf_write::bf_write( const char *pDebugName, void *pData, int nBytes, int nBits )
|
|
{
|
|
DEBUG_LINK_CHECK;
|
|
m_bAssertOnOverflow = true;
|
|
m_pDebugName = pDebugName;
|
|
StartWriting( pData, nBytes, 0, nBits );
|
|
}
|
|
|
|
bf_write::bf_write( void *pData, int nBytes, int nBits )
|
|
{
|
|
m_bAssertOnOverflow = true;
|
|
m_pDebugName = NULL;
|
|
StartWriting( pData, nBytes, 0, nBits );
|
|
}
|
|
|
|
void bf_write::StartWriting( void *pData, int nBytes, int iStartBit, int nBits )
|
|
{
|
|
// 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 )
|
|
{
|
|
m_nDataBits = nBytes << 3;
|
|
}
|
|
else
|
|
{
|
|
Assert( nBits <= nBytes*8 );
|
|
m_nDataBits = nBits;
|
|
}
|
|
|
|
m_iCurBit = iStartBit;
|
|
m_bOverflow = false;
|
|
}
|
|
|
|
void bf_write::Reset()
|
|
{
|
|
m_iCurBit = 0;
|
|
m_bOverflow = false;
|
|
}
|
|
|
|
|
|
void bf_write::SetAssertOnOverflow( bool bAssert )
|
|
{
|
|
m_bAssertOnOverflow = bAssert;
|
|
}
|
|
|
|
|
|
const char* bf_write::GetDebugName()
|
|
{
|
|
return m_pDebugName;
|
|
}
|
|
|
|
|
|
void bf_write::SetDebugName( const char *pDebugName )
|
|
{
|
|
m_pDebugName = pDebugName;
|
|
}
|
|
|
|
|
|
void bf_write::SeekToBit( int bitPos )
|
|
{
|
|
m_iCurBit = bitPos;
|
|
}
|
|
|
|
|
|
// Sign bit comes first
|
|
void bf_write::WriteSBitLong( int data, int numbits )
|
|
{
|
|
// Do we have a valid # of bits to encode with?
|
|
Assert( numbits >= 1 );
|
|
|
|
// Note: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
|
|
// (Some old code writes direct integers right into the buffer).
|
|
if(data < 0)
|
|
{
|
|
#ifdef _DEBUG
|
|
if( numbits < 32 )
|
|
{
|
|
// Make sure it doesn't overflow.
|
|
|
|
if( data < 0 )
|
|
{
|
|
Assert( data >= -(BitForBitnum(numbits-1)) );
|
|
}
|
|
else
|
|
{
|
|
Assert( data < (BitForBitnum(numbits-1)) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
WriteUBitLong( (unsigned int)(0x80000000 + data), numbits - 1, false );
|
|
WriteOneBit( 1 );
|
|
}
|
|
else
|
|
{
|
|
WriteUBitLong((unsigned int)data, numbits - 1);
|
|
WriteOneBit( 0 );
|
|
}
|
|
}
|
|
|
|
#if _WIN32
|
|
inline unsigned int BitCountNeededToEncode(unsigned int data)
|
|
{
|
|
#if defined(_X360)
|
|
return (32 - CountLeadingZeros(data+1)) - 1;
|
|
#else
|
|
unsigned long firstBit;
|
|
_BitScanReverse(&firstBit,data+1);
|
|
return firstBit;
|
|
#endif
|
|
}
|
|
#endif // _WIN32
|
|
|
|
// writes an unsigned integer with variable bit length
|
|
void bf_write::WriteUBitVar( unsigned int n )
|
|
{
|
|
if ( n < 16 )
|
|
WriteUBitLong( n, 6 );
|
|
else
|
|
if ( n < 256 )
|
|
WriteUBitLong( ( n & 15 ) | 16 | ( ( n & ( 128 | 64 | 32 | 16 ) ) << 2 ), 10 );
|
|
else
|
|
if ( n < 4096 )
|
|
WriteUBitLong( ( n & 15 ) | 32 | ( ( n & ( 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 ) ) << 2 ), 14 );
|
|
else
|
|
{
|
|
WriteUBitLong( ( n & 15 ) | 48, 6 );
|
|
WriteUBitLong( ( n >> 4 ), 32 - 4 );
|
|
}
|
|
}
|
|
|
|
void bf_write::WriteVarInt32( uint32 data )
|
|
{
|
|
// Check if align and we have room, slow path if not
|
|
if ( (m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarint32Bytes * 8 ) <= m_nDataBits)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
else // Slow path
|
|
{
|
|
while ( data > 0x7F )
|
|
{
|
|
WriteUBitLong( (data & 0x7F) | 0x80, 8 );
|
|
data >>= 7;
|
|
}
|
|
WriteUBitLong( data & 0x7F, 8 );
|
|
}
|
|
}
|
|
|
|
void bf_write::WriteVarInt64( uint64 data )
|
|
{
|
|
// Check if align and we have room, slow path if not
|
|
if ( (m_iCurBit & 7) == 0 && (m_iCurBit + bitbuf::kMaxVarintBytes * 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;
|
|
}
|
|
}
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
void bf_write::WriteSignedVarInt32( int32 data )
|
|
{
|
|
WriteVarInt32( bitbuf::ZigZagEncode32( data ) );
|
|
}
|
|
|
|
void bf_write::WriteSignedVarInt64( int64 data )
|
|
{
|
|
WriteVarInt64( bitbuf::ZigZagEncode64( data ) );
|
|
}
|
|
|
|
int bf_write::ByteSizeVarInt32( uint32 data )
|
|
{
|
|
int size = 1;
|
|
while ( data > 0x7F ) {
|
|
size++;
|
|
data >>= 7;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int bf_write::ByteSizeVarInt64( uint64 data )
|
|
{
|
|
int size = 1;
|
|
while ( data > 0x7F ) {
|
|
size++;
|
|
data >>= 7;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int bf_write::ByteSizeSignedVarInt32( int32 data )
|
|
{
|
|
return ByteSizeVarInt32( bitbuf::ZigZagEncode32( data ) );
|
|
}
|
|
|
|
int bf_write::ByteSizeSignedVarInt64( int64 data )
|
|
{
|
|
return ByteSizeVarInt64( bitbuf::ZigZagEncode64( data ) );
|
|
}
|
|
|
|
void bf_write::WriteBitLong(unsigned int data, int numbits, bool bSigned)
|
|
{
|
|
if(bSigned)
|
|
WriteSBitLong((int)data, numbits);
|
|
else
|
|
WriteUBitLong(data, numbits);
|
|
}
|
|
|
|
bool bf_write::WriteBits(const void *pInData, int nBits)
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::WriteBits" );
|
|
#endif
|
|
|
|
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;
|
|
|
|
Q_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 );
|
|
outWord &= g_BitWriteMasks[iBitsRight][32]; // clear rest of beginning DWORD
|
|
|
|
// 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();
|
|
}
|
|
|
|
bool bf_write::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();
|
|
}
|
|
|
|
|
|
void bf_write::WriteBitAngle( float fAngle, int numbits )
|
|
{
|
|
int d;
|
|
unsigned int mask;
|
|
unsigned int shift;
|
|
|
|
shift = BitForBitnum(numbits);
|
|
mask = shift - 1;
|
|
|
|
d = (int)( (fAngle / 360.0) * shift );
|
|
d &= mask;
|
|
|
|
WriteUBitLong((unsigned int)d, numbits);
|
|
}
|
|
|
|
void bf_write::WriteBitCoordMP( const float f, EBitCoordType coordType )
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::WriteBitCoordMP" );
|
|
#endif
|
|
bool bIntegral = ( coordType == kCW_Integral );
|
|
bool bLowPrecision = ( coordType == kCW_LowPrecision );
|
|
|
|
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 );
|
|
|
|
WriteOneBit( bInBounds );
|
|
|
|
if ( bIntegral )
|
|
{
|
|
// Send the sign bit
|
|
WriteOneBit( intval );
|
|
if ( intval )
|
|
{
|
|
WriteOneBit( signbit );
|
|
// Send the integer if we have one.
|
|
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
|
|
intval--;
|
|
if ( bInBounds )
|
|
{
|
|
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP );
|
|
}
|
|
else
|
|
{
|
|
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Send the bit flags that indicate whether we have an integer part and/or a fraction part.
|
|
WriteOneBit( intval );
|
|
// Send the sign bit
|
|
WriteOneBit( signbit );
|
|
|
|
if ( intval )
|
|
{
|
|
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
|
|
intval--;
|
|
if ( bInBounds )
|
|
{
|
|
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP );
|
|
}
|
|
else
|
|
{
|
|
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS );
|
|
}
|
|
}
|
|
WriteUBitLong( (unsigned int)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
|
|
}
|
|
}
|
|
|
|
void bf_write::WriteBitCellCoord( const float f, int bits, EBitCoordType coordType )
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::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 bf_write::WriteBitCoord(const float f)
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::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 )
|
|
{
|
|
// 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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void bf_write::WriteBitFloat(float val)
|
|
{
|
|
int32 intVal;
|
|
|
|
Assert(sizeof(int32) == sizeof(float));
|
|
Assert(sizeof(float) == 4);
|
|
|
|
intVal = *((int32*)&val);
|
|
WriteUBitLong( intVal, 32 );
|
|
}
|
|
|
|
void bf_write::WriteBitVec3Coord( const Vector& 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 bf_write::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 bf_write::WriteBitVec3Normal( const Vector& 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 bf_write::WriteBitAngles( const QAngle& fa )
|
|
{
|
|
// FIXME:
|
|
Vector tmp( fa.x, fa.y, fa.z );
|
|
WriteBitVec3Coord( tmp );
|
|
}
|
|
|
|
void bf_write::WriteChar(int val)
|
|
{
|
|
WriteSBitLong(val, sizeof(char) << 3);
|
|
}
|
|
|
|
void bf_write::WriteByte( unsigned int val )
|
|
{
|
|
WriteUBitLong(val, sizeof(unsigned char) << 3);
|
|
}
|
|
|
|
void bf_write::WriteShort(int val)
|
|
{
|
|
WriteSBitLong(val, sizeof(short) << 3);
|
|
}
|
|
|
|
void bf_write::WriteWord( unsigned int val )
|
|
{
|
|
WriteUBitLong(val, sizeof(unsigned short) << 3);
|
|
}
|
|
|
|
void bf_write::WriteLong(int32 val)
|
|
{
|
|
WriteSBitLong(val, sizeof(int32) << 3);
|
|
}
|
|
|
|
void bf_write::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(int32) << 3);
|
|
WriteUBitLong(pLongs[*idx], sizeof(int32) << 3);
|
|
}
|
|
|
|
void bf_write::WriteFloat(float val)
|
|
{
|
|
// Pre-swap the float, since WriteBits writes raw data
|
|
LittleFloat( &val, &val );
|
|
|
|
WriteBits(&val, sizeof(val) << 3);
|
|
}
|
|
|
|
bool bf_write::WriteBytes( const void *pBuf, int nBytes )
|
|
{
|
|
return WriteBits(pBuf, nBytes << 3);
|
|
}
|
|
|
|
bool bf_write::WriteString(const char *pStr)
|
|
{
|
|
if(pStr)
|
|
{
|
|
do
|
|
{
|
|
WriteChar( *pStr );
|
|
++pStr;
|
|
} while( *(pStr-1) != 0 );
|
|
}
|
|
else
|
|
{
|
|
WriteChar( 0 );
|
|
}
|
|
|
|
return !IsOverflowed();
|
|
}
|
|
|
|
bool bf_write::WriteString(const wchar_t *pStr)
|
|
{
|
|
if(pStr)
|
|
{
|
|
do
|
|
{
|
|
WriteShort( *pStr );
|
|
++pStr;
|
|
} while( *(pStr-1) != 0 );
|
|
}
|
|
else
|
|
{
|
|
WriteShort( 0 );
|
|
}
|
|
|
|
return !IsOverflowed();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
// old_bf_read
|
|
// ---------------------------------------------------------------------------------------- //
|
|
|
|
old_bf_read::old_bf_read()
|
|
{
|
|
DEBUG_LINK_CHECK;
|
|
m_pData = NULL;
|
|
m_nDataBytes = 0;
|
|
m_nDataBits = -1; // set to -1 so we overflow on any operation
|
|
m_iCurBit = 0;
|
|
m_bOverflow = false;
|
|
m_bAssertOnOverflow = true;
|
|
m_pDebugName = NULL;
|
|
}
|
|
|
|
old_bf_read::old_bf_read( const void *pData, int nBytes, int nBits )
|
|
{
|
|
m_bAssertOnOverflow = true;
|
|
StartReading( pData, nBytes, 0, nBits );
|
|
}
|
|
|
|
old_bf_read::old_bf_read( const char *pDebugName, const void *pData, int nBytes, int nBits )
|
|
{
|
|
m_bAssertOnOverflow = true;
|
|
m_pDebugName = pDebugName;
|
|
StartReading( pData, nBytes, 0, nBits );
|
|
}
|
|
|
|
void old_bf_read::StartReading( const void *pData, int nBytes, int iStartBit, int nBits )
|
|
{
|
|
// Make sure we're dword aligned.
|
|
Assert(((uintp)pData & 3) == 0);
|
|
|
|
m_pData = (unsigned char*)pData;
|
|
m_nDataBytes = nBytes;
|
|
|
|
if ( nBits == -1 )
|
|
{
|
|
m_nDataBits = m_nDataBytes << 3;
|
|
}
|
|
else
|
|
{
|
|
Assert( nBits <= nBytes*8 );
|
|
m_nDataBits = nBits;
|
|
}
|
|
|
|
m_iCurBit = iStartBit;
|
|
m_bOverflow = false;
|
|
}
|
|
|
|
void old_bf_read::Reset()
|
|
{
|
|
m_iCurBit = 0;
|
|
m_bOverflow = false;
|
|
}
|
|
|
|
void old_bf_read::SetAssertOnOverflow( bool bAssert )
|
|
{
|
|
m_bAssertOnOverflow = bAssert;
|
|
}
|
|
|
|
const char* old_bf_read::GetDebugName()
|
|
{
|
|
return m_pDebugName;
|
|
}
|
|
|
|
void old_bf_read::SetDebugName( const char *pName )
|
|
{
|
|
m_pDebugName = pName;
|
|
}
|
|
|
|
unsigned int old_bf_read::CheckReadUBitLong(int numbits)
|
|
{
|
|
// Ok, just read bits out.
|
|
int i, nBitValue;
|
|
unsigned int r = 0;
|
|
|
|
for(i=0; i < numbits; i++)
|
|
{
|
|
nBitValue = ReadOneBitNoCheck();
|
|
r |= nBitValue << i;
|
|
}
|
|
m_iCurBit -= numbits;
|
|
|
|
return r;
|
|
}
|
|
|
|
void old_bf_read::ReadBits(void *pOutData, int nBits)
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::ReadBits" );
|
|
#endif
|
|
|
|
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 = ReadUBitLong(8);
|
|
++pOut;
|
|
nBitsLeft -= 8;
|
|
}
|
|
|
|
// read remaining bits
|
|
if ( nBitsLeft )
|
|
{
|
|
*pOut = ReadUBitLong(nBitsLeft);
|
|
}
|
|
|
|
}
|
|
|
|
float old_bf_read::ReadBitAngle( int numbits )
|
|
{
|
|
float fReturn;
|
|
int i;
|
|
float shift;
|
|
|
|
shift = (float)( BitForBitnum(numbits) );
|
|
|
|
i = ReadUBitLong( numbits );
|
|
fReturn = (float)i * (360.0 / shift);
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
unsigned int old_bf_read::PeekUBitLong( int numbits )
|
|
{
|
|
unsigned int r;
|
|
int i, nBitValue;
|
|
#ifdef BIT_VERBOSE
|
|
int nShifts = numbits;
|
|
#endif
|
|
|
|
old_bf_read savebf;
|
|
|
|
savebf = *this; // Save current state info
|
|
|
|
r = 0;
|
|
for(i=0; i < numbits; i++)
|
|
{
|
|
nBitValue = ReadOneBit();
|
|
|
|
// Append to current stream
|
|
if ( nBitValue )
|
|
{
|
|
r |= BitForBitnum(i);
|
|
}
|
|
}
|
|
|
|
*this = savebf;
|
|
|
|
#ifdef BIT_VERBOSE
|
|
Con_Printf( "PeekBitLong: %i %i\n", nShifts, (unsigned int)r );
|
|
#endif
|
|
|
|
return r;
|
|
}
|
|
|
|
// Append numbits least significant bits from data to the current bit stream
|
|
int old_bf_read::ReadSBitLong( int numbits )
|
|
{
|
|
int r, sign;
|
|
|
|
r = ReadUBitLong(numbits - 1);
|
|
|
|
// Note: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
|
|
// (Some old code writes direct integers right into the buffer).
|
|
sign = ReadOneBit();
|
|
if(sign)
|
|
r = -((BitForBitnum(numbits-1)) - r);
|
|
|
|
return r;
|
|
}
|
|
|
|
const byte g_BitMask[8] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
|
|
const byte g_TrailingMask[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
|
|
|
|
inline int old_bf_read::CountRunOfZeros()
|
|
{
|
|
int bits = 0;
|
|
if ( m_iCurBit + 32 < m_nDataBits )
|
|
{
|
|
#if !FAST_BIT_SCAN
|
|
while (true)
|
|
{
|
|
int value = (m_pData[m_iCurBit >> 3] & g_BitMask[m_iCurBit & 7]);
|
|
++m_iCurBit;
|
|
if ( value )
|
|
return bits;
|
|
++bits;
|
|
}
|
|
#else
|
|
while (true)
|
|
{
|
|
int value = (m_pData[m_iCurBit >> 3] & g_TrailingMask[m_iCurBit & 7]);
|
|
if ( !value )
|
|
{
|
|
int zeros = (8-(m_iCurBit&7));
|
|
bits += zeros;
|
|
m_iCurBit += zeros;
|
|
}
|
|
else
|
|
{
|
|
int zeros = CountTrailingZeros(value) - (m_iCurBit & 7);
|
|
m_iCurBit += zeros + 1;
|
|
bits += zeros;
|
|
return bits;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
while ( ReadOneBit() == 0 )
|
|
bits++;
|
|
}
|
|
return bits;
|
|
}
|
|
|
|
unsigned int old_bf_read::ReadUBitVar()
|
|
{
|
|
unsigned int ret = ReadUBitLong( 6 );
|
|
switch( ret & ( 16 | 32 ) )
|
|
{
|
|
case 16:
|
|
ret = ( ret & 15 ) | ( ReadUBitLong( 4 ) << 4 );
|
|
Assert( ret >= 16);
|
|
break;
|
|
|
|
case 32:
|
|
ret = ( ret & 15 ) | ( ReadUBitLong( 8 ) << 4 );
|
|
Assert( ret >= 256);
|
|
break;
|
|
case 48:
|
|
ret = ( ret & 15 ) | ( ReadUBitLong( 32 - 4 ) << 4 );
|
|
Assert( ret >= 4096 );
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
// 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 old_bf_read::ReadVarInt32()
|
|
{
|
|
uint32 result = 0;
|
|
int count = 0;
|
|
uint32 b;
|
|
|
|
do
|
|
{
|
|
if ( count == bitbuf::kMaxVarint32Bytes )
|
|
{
|
|
// If we get here it means that the fifth bit had its
|
|
// high bit set, which implies corrupt data.
|
|
Assert( 0 );
|
|
return result;
|
|
}
|
|
b = ReadUBitLong( 8 );
|
|
result |= (b & 0x7F) << (7 * count);
|
|
++count;
|
|
} while (b & 0x80);
|
|
|
|
return result;
|
|
}
|
|
|
|
uint64 old_bf_read::ReadVarInt64()
|
|
{
|
|
uint64 result = 0;
|
|
int count = 0;
|
|
uint64 b;
|
|
|
|
do
|
|
{
|
|
if ( count == bitbuf::kMaxVarintBytes )
|
|
{
|
|
return result;
|
|
}
|
|
b = ReadUBitLong( 8 );
|
|
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
|
|
++count;
|
|
} while (b & 0x80);
|
|
|
|
return result;
|
|
}
|
|
|
|
unsigned int old_bf_read::ReadBitLong(int numbits, bool bSigned)
|
|
{
|
|
if(bSigned)
|
|
return (unsigned int)ReadSBitLong(numbits);
|
|
else
|
|
return ReadUBitLong(numbits);
|
|
}
|
|
|
|
|
|
// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants)
|
|
float old_bf_read::ReadBitCoord (void)
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::ReadBitCoord" );
|
|
#endif
|
|
int intval=0,fractval=0,signbit=0;
|
|
float value = 0.0;
|
|
|
|
|
|
// 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 )
|
|
{
|
|
// Read the sign bit
|
|
signbit = ReadOneBit();
|
|
|
|
// If there's an integer, read it in
|
|
if ( intval )
|
|
{
|
|
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
|
|
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
|
|
}
|
|
|
|
// If there's a fraction, read it in
|
|
if ( fractval )
|
|
{
|
|
fractval = ReadUBitLong( COORD_FRACTIONAL_BITS );
|
|
}
|
|
|
|
// Calculate the correct floating point value
|
|
value = intval + ((float)fractval * COORD_RESOLUTION);
|
|
|
|
// Fixup the sign if negative.
|
|
if ( signbit )
|
|
value = -value;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
float old_bf_read::ReadBitCoordMP( EBitCoordType coordType )
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::ReadBitCoordMP" );
|
|
#endif
|
|
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 )
|
|
{
|
|
// Read the required integer and fraction flags
|
|
intval = ReadOneBit();
|
|
// If we got either parse them, otherwise it's a zero.
|
|
if ( intval )
|
|
{
|
|
// 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 = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
|
|
}
|
|
else
|
|
{
|
|
value = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
|
|
}
|
|
}
|
|
}
|
|
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 )
|
|
{
|
|
if ( bInBounds )
|
|
{
|
|
intval = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
|
|
}
|
|
else
|
|
{
|
|
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
|
|
}
|
|
}
|
|
|
|
// 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 old_bf_read::ReadBitCellCoord( int bits, EBitCoordType coordType )
|
|
{
|
|
#if defined( BB_PROFILING )
|
|
VPROF( "bf_write::ReadBitCoordMP" );
|
|
#endif
|
|
bool bIntegral = ( coordType == kCW_Integral );
|
|
bool bLowPrecision = ( coordType == kCW_LowPrecision );
|
|
|
|
int intval=0,fractval=0;
|
|
float value = 0.0;
|
|
|
|
if ( bIntegral )
|
|
{
|
|
value = ReadUBitLong( bits );
|
|
}
|
|
else
|
|
{
|
|
intval = ReadUBitLong( bits );
|
|
|
|
// 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 ) );
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
void old_bf_read::ReadBitVec3Coord( Vector& fa )
|
|
{
|
|
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();
|
|
}
|
|
|
|
float old_bf_read::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;
|
|
}
|
|
|
|
void old_bf_read::ReadBitVec3Normal( Vector& 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 old_bf_read::ReadBitAngles( QAngle& fa )
|
|
{
|
|
Vector tmp;
|
|
ReadBitVec3Coord( tmp );
|
|
fa.Init( tmp.x, tmp.y, tmp.z );
|
|
}
|
|
|
|
int old_bf_read::ReadChar()
|
|
{
|
|
return ReadSBitLong(sizeof(char) << 3);
|
|
}
|
|
|
|
int old_bf_read::ReadByte()
|
|
{
|
|
return ReadUBitLong(sizeof(unsigned char) << 3);
|
|
}
|
|
|
|
int old_bf_read::ReadShort()
|
|
{
|
|
return ReadSBitLong(sizeof(short) << 3);
|
|
}
|
|
|
|
int old_bf_read::ReadWord()
|
|
{
|
|
return ReadUBitLong(sizeof(unsigned short) << 3);
|
|
}
|
|
|
|
int32 old_bf_read::ReadLong()
|
|
{
|
|
return ReadSBitLong(sizeof(int32) << 3);
|
|
}
|
|
|
|
int64 old_bf_read::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(int32) << 3);
|
|
pLongs[*idx] = ReadUBitLong(sizeof(int32) << 3);
|
|
|
|
return retval;
|
|
}
|
|
|
|
float old_bf_read::ReadFloat()
|
|
{
|
|
float ret;
|
|
Assert( sizeof(ret) == 4 );
|
|
ReadBits(&ret, 32);
|
|
|
|
// Swap the float, since ReadBits reads raw data
|
|
LittleFloat( &ret, &ret );
|
|
return ret;
|
|
}
|
|
|
|
bool old_bf_read::ReadBytes(void *pOut, int nBytes)
|
|
{
|
|
ReadBits(pOut, nBytes << 3);
|
|
return !IsOverflowed();
|
|
}
|
|
|
|
bool old_bf_read::ReadString( char *pStr, int maxLen, bool bLine, int *pOutNumChars )
|
|
{
|
|
Assert( maxLen != 0 );
|
|
|
|
bool bTooSmall = false;
|
|
int iChar = 0;
|
|
while(1)
|
|
{
|
|
char val = ReadChar();
|
|
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.
|
|
Assert( iChar < maxLen );
|
|
pStr[iChar] = 0;
|
|
|
|
if ( pOutNumChars )
|
|
*pOutNumChars = iChar;
|
|
|
|
return !IsOverflowed() && !bTooSmall;
|
|
}
|
|
|
|
bool old_bf_read::ReadWString( wchar_t *pStr, int maxLen, bool bLine, int *pOutNumChars )
|
|
{
|
|
Assert( maxLen != 0 );
|
|
|
|
bool bTooSmall = false;
|
|
int iChar = 0;
|
|
while(1)
|
|
{
|
|
wchar val = ReadShort();
|
|
if ( val == 0 )
|
|
break;
|
|
else if ( bLine && val == L'\n' )
|
|
break;
|
|
|
|
if ( iChar < (maxLen-1) )
|
|
{
|
|
pStr[iChar] = val;
|
|
++iChar;
|
|
}
|
|
else
|
|
{
|
|
bTooSmall = true;
|
|
}
|
|
}
|
|
|
|
// Make sure it's null-terminated.
|
|
Assert( iChar < maxLen );
|
|
pStr[iChar] = 0;
|
|
|
|
if ( pOutNumChars )
|
|
*pOutNumChars = iChar;
|
|
|
|
return !IsOverflowed() && !bTooSmall;
|
|
}
|
|
|
|
|
|
char* old_bf_read::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;
|
|
}
|
|
|
|
void old_bf_read::ExciseBits( int startbit, int bitstoremove )
|
|
{
|
|
int endbit = startbit + bitstoremove;
|
|
int remaining_to_end = m_nDataBits - endbit;
|
|
|
|
bf_write temp;
|
|
temp.StartWriting( (void *)m_pData, m_nDataBits << 3, startbit );
|
|
|
|
Seek( endbit );
|
|
|
|
for ( int i = 0; i < remaining_to_end; i++ )
|
|
{
|
|
temp.WriteOneBit( ReadOneBit() );
|
|
}
|
|
|
|
Seek( startbit );
|
|
|
|
m_nDataBits -= bitstoremove;
|
|
m_nDataBytes = m_nDataBits >> 3;
|
|
}
|
|
|
|
|