774 lines
17 KiB
C
774 lines
17 KiB
C
//=======================================================================
|
|
// Copyright XashXT Group 2010 ©
|
|
// net_buffer.c - network bitbuffer io functions
|
|
//=======================================================================
|
|
|
|
#include "common.h"
|
|
#include "protocol.h"
|
|
#include "net_buffer.h"
|
|
|
|
// precalculated bit masks for WriteUBitLong.
|
|
// Using these tables instead of doing the calculations
|
|
// gives a 33% speedup in WriteUBitLong.
|
|
|
|
static dword BitWriteMasks[32][33];
|
|
static dword ExtraMasks[32];
|
|
|
|
short BF_BigShort( short swap )
|
|
{
|
|
short *s = &swap;
|
|
|
|
__asm {
|
|
mov ebx, s
|
|
mov al, [ebx+1]
|
|
mov ah, [ebx ]
|
|
mov [ebx], ax
|
|
}
|
|
return *s;
|
|
}
|
|
|
|
void BF_InitMasks( void )
|
|
{
|
|
uint startbit, endbit;
|
|
uint maskBit, nBitsLeft;
|
|
|
|
for( startbit = 0; startbit < 32; startbit++ )
|
|
{
|
|
for( nBitsLeft = 0; nBitsLeft < 33; nBitsLeft++ )
|
|
{
|
|
endbit = startbit + nBitsLeft;
|
|
|
|
BitWriteMasks[startbit][nBitsLeft] = BIT( startbit ) - 1;
|
|
if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~(BIT( endbit ) - 1 );
|
|
}
|
|
}
|
|
|
|
for( maskBit = 0; maskBit < 32; maskBit++ )
|
|
ExtraMasks[maskBit] = BIT( maskBit ) - 1;
|
|
}
|
|
|
|
void BF_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
|
|
{
|
|
bf->pDebugName = pDebugName;
|
|
|
|
BF_StartWriting( bf, pData, nBytes, 0, nMaxBits );
|
|
}
|
|
|
|
void BF_StartWriting( sizebuf_t *bf, void *pData, int nBytes, int iStartBit, int nBits )
|
|
{
|
|
// make sure it's dword aligned and padded.
|
|
// Assert(( nBytes % 4 ) == 0 );
|
|
Assert(((dword)pData & 3 ) == 0 );
|
|
|
|
bf->pData = (byte *)pData;
|
|
|
|
if( nBits == -1 )
|
|
{
|
|
bf->nDataBits = nBytes << 3;
|
|
}
|
|
else
|
|
{
|
|
Assert( nBits <= nBytes * 8 );
|
|
bf->nDataBits = nBits;
|
|
}
|
|
|
|
bf->iCurBit = iStartBit;
|
|
bf->bOverflow = false;
|
|
}
|
|
|
|
/*
|
|
=======================
|
|
MSG_Clear
|
|
|
|
for clearing overflowed buffer
|
|
=======================
|
|
*/
|
|
void BF_Clear( sizebuf_t *bf )
|
|
{
|
|
bf->iCurBit = 0;
|
|
bf->bOverflow = false;
|
|
}
|
|
|
|
static qboolean BF_Overflow( sizebuf_t *bf, int nBits )
|
|
{
|
|
if( bf->iCurBit + nBits > bf->nDataBits )
|
|
bf->bOverflow = true;
|
|
return bf->bOverflow;
|
|
}
|
|
|
|
qboolean BF_CheckOverflow( sizebuf_t *bf )
|
|
{
|
|
ASSERT( bf );
|
|
|
|
return BF_Overflow( bf, 0 );
|
|
}
|
|
|
|
void BF_SeekToBit( sizebuf_t *bf, int bitPos )
|
|
{
|
|
bf->iCurBit = bitPos;
|
|
}
|
|
|
|
void BF_SeekToByte( sizebuf_t *bf, int bytePos )
|
|
{
|
|
bf->iCurBit = bytePos << 3;
|
|
}
|
|
|
|
void BF_WriteOneBit( sizebuf_t *bf, int nValue )
|
|
{
|
|
if( !BF_Overflow( bf, 1 ))
|
|
{
|
|
if( nValue ) bf->pData[bf->iCurBit>>3] |= (1 << ( bf->iCurBit & 7 ));
|
|
else bf->pData[bf->iCurBit>>3] &= ~(1 << ( bf->iCurBit & 7 ));
|
|
|
|
bf->iCurBit++;
|
|
}
|
|
}
|
|
|
|
void BF_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bCheckRange )
|
|
{
|
|
#ifdef _NETDEBUG
|
|
// make sure it doesn't overflow.
|
|
if( bCheckRange && numbits < 32 )
|
|
{
|
|
if( curData >= (dword)BIT( numbits ))
|
|
MsgDev( D_ERROR, "Write%s: out of range value!\n", bf->pDebugName );
|
|
}
|
|
#endif
|
|
Assert( numbits >= 0 && numbits <= 32 );
|
|
|
|
// bounds checking..
|
|
if(( bf->iCurBit + numbits ) > bf->nDataBits )
|
|
{
|
|
bf->bOverflow = true;
|
|
bf->iCurBit = bf->nDataBits;
|
|
}
|
|
else
|
|
{
|
|
int nBitsLeft = numbits;
|
|
int iCurBit = bf->iCurBit;
|
|
uint iDWord = iCurBit >> 5; // Mask in a dword.
|
|
dword iCurBitMasked;
|
|
int nBitsWritten;
|
|
|
|
Assert(( iDWord * 4 + sizeof( long )) <= (uint)BF_GetMaxBytes( bf ));
|
|
|
|
iCurBitMasked = iCurBit & 31;
|
|
((dword *)bf->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
|
((dword *)bf->pData)[iDWord] |= curData << iCurBitMasked;
|
|
|
|
// did it span a dword?
|
|
nBitsWritten = 32 - iCurBitMasked;
|
|
|
|
if( nBitsWritten < nBitsLeft )
|
|
{
|
|
nBitsLeft -= nBitsWritten;
|
|
iCurBit += nBitsWritten;
|
|
curData >>= nBitsWritten;
|
|
|
|
iCurBitMasked = iCurBit & 31;
|
|
((dword *)bf->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
|
((dword *)bf->pData)[iDWord+1] |= curData << iCurBitMasked;
|
|
}
|
|
bf->iCurBit += numbits;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=======================
|
|
BF_WriteSBitLong
|
|
|
|
sign bit comes first
|
|
=======================
|
|
*/
|
|
void BF_WriteSBitLong( sizebuf_t *bf, 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 _NETDEBUG
|
|
if( numbits < 32 )
|
|
{
|
|
// Make sure it doesn't overflow.
|
|
if( data < 0 )
|
|
{
|
|
Assert( data >= -BIT( numbits - 1 ));
|
|
}
|
|
else
|
|
{
|
|
Assert( data < BIT( numbits - 1 ));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BF_WriteUBitLongExt( bf, (uint)( 0x80000000 + data ), numbits - 1, false );
|
|
BF_WriteOneBit( bf, 1 );
|
|
}
|
|
else
|
|
{
|
|
BF_WriteUBitLong( bf, (uint)data, numbits - 1 );
|
|
BF_WriteOneBit( bf, 0 );
|
|
}
|
|
}
|
|
|
|
void BF_WriteBitLong( sizebuf_t *bf, uint data, int numbits, qboolean bSigned )
|
|
{
|
|
if( bSigned )
|
|
BF_WriteSBitLong( bf, (int)data, numbits );
|
|
else BF_WriteUBitLong( bf, data, numbits );
|
|
}
|
|
|
|
qboolean BF_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
|
|
{
|
|
byte *pOut = (byte *)pData;
|
|
int nBitsLeft = nBits;
|
|
|
|
// get output dword-aligned.
|
|
while((( dword )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
|
{
|
|
BF_WriteUBitLongExt( bf, *pOut, 8, false );
|
|
|
|
nBitsLeft -= 8;
|
|
++pOut;
|
|
}
|
|
|
|
// read dwords.
|
|
while( nBitsLeft >= 32 )
|
|
{
|
|
BF_WriteUBitLongExt( bf, *(( dword *)pOut ), 32, false );
|
|
|
|
pOut += sizeof( dword );
|
|
nBitsLeft -= 32;
|
|
}
|
|
|
|
// read the remaining bytes.
|
|
while( nBitsLeft >= 8 )
|
|
{
|
|
BF_WriteUBitLongExt( bf, *pOut, 8, false );
|
|
|
|
nBitsLeft -= 8;
|
|
++pOut;
|
|
}
|
|
|
|
// Read the remaining bits.
|
|
if( nBitsLeft )
|
|
{
|
|
BF_WriteUBitLongExt( bf, *pOut, nBitsLeft, false );
|
|
}
|
|
|
|
return !bf->bOverflow;
|
|
}
|
|
|
|
|
|
void BF_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits )
|
|
{
|
|
uint mask, shift;
|
|
int d;
|
|
|
|
// clamp the angle before receiving
|
|
if( fAngle > 360 ) fAngle -= 360;
|
|
else if( fAngle < 0 ) fAngle += 360;
|
|
|
|
shift = ( 1 << numbits );
|
|
mask = shift - 1;
|
|
|
|
d = (int)( fAngle * shift ) / 360;
|
|
d &= mask;
|
|
|
|
BF_WriteUBitLong( bf, (uint)d, numbits );
|
|
}
|
|
|
|
void BF_WriteBitCoord( sizebuf_t *bf, const float f )
|
|
{
|
|
int signbit = ( f <= -COORD_RESOLUTION );
|
|
int fractval = abs(( int )( f * COORD_DENOMINATOR )) & ( COORD_DENOMINATOR - 1 );
|
|
int intval = (int)abs( f );
|
|
|
|
// Send the bit flags that indicate whether we have an integer part and/or a fraction part.
|
|
BF_WriteOneBit( bf, intval );
|
|
BF_WriteOneBit( bf, fractval );
|
|
|
|
if( intval || fractval )
|
|
{
|
|
// send the sign bit
|
|
BF_WriteOneBit( bf, 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--;
|
|
BF_WriteUBitLong( bf, (uint)intval, COORD_INTEGER_BITS );
|
|
}
|
|
|
|
// send the fraction if we have one
|
|
if( fractval )
|
|
{
|
|
BF_WriteUBitLong( bf, (uint)fractval, COORD_FRACTIONAL_BITS );
|
|
}
|
|
}
|
|
}
|
|
|
|
void BF_WriteBitFloat( sizebuf_t *bf, float val )
|
|
{
|
|
long intVal;
|
|
|
|
ASSERT( sizeof( long ) == sizeof( float ));
|
|
ASSERT( sizeof( float ) == 4 );
|
|
|
|
intVal = *((long *)&val );
|
|
BF_WriteUBitLong( bf, intVal, 32 );
|
|
}
|
|
|
|
void BF_WriteBitVec3Coord( sizebuf_t *bf, const float *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 );
|
|
|
|
BF_WriteOneBit( bf, xflag );
|
|
BF_WriteOneBit( bf, yflag );
|
|
BF_WriteOneBit( bf, zflag );
|
|
|
|
if( xflag ) BF_WriteBitCoord( bf, fa[0] );
|
|
if( yflag ) BF_WriteBitCoord( bf, fa[1] );
|
|
if( zflag ) BF_WriteBitCoord( bf, fa[2] );
|
|
}
|
|
|
|
void BF_WriteBitNormal( sizebuf_t *bf, float f )
|
|
{
|
|
int signbit = ( f <= -NORMAL_RESOLUTION );
|
|
uint fractval = abs(( int )(f * NORMAL_DENOMINATOR ));
|
|
|
|
if( fractval > NORMAL_DENOMINATOR )
|
|
fractval = NORMAL_DENOMINATOR;
|
|
|
|
// send the sign bit
|
|
BF_WriteOneBit( bf, signbit );
|
|
|
|
// send the fractional component
|
|
BF_WriteUBitLong( bf, fractval, NORMAL_FRACTIONAL_BITS );
|
|
}
|
|
|
|
void BF_WriteBitVec3Normal( sizebuf_t *bf, const float *fa )
|
|
{
|
|
int xflag, yflag;
|
|
int signbit;
|
|
|
|
xflag = ( fa[0] >= NORMAL_RESOLUTION ) || ( fa[0] <= -NORMAL_RESOLUTION );
|
|
yflag = ( fa[1] >= NORMAL_RESOLUTION ) || ( fa[1] <= -NORMAL_RESOLUTION );
|
|
|
|
BF_WriteOneBit( bf, xflag );
|
|
BF_WriteOneBit( bf, yflag );
|
|
|
|
if( xflag ) BF_WriteBitNormal( bf, fa[0] );
|
|
if( yflag ) BF_WriteBitNormal( bf, fa[1] );
|
|
|
|
// Write z sign bit
|
|
signbit = ( fa[2] <= -NORMAL_RESOLUTION );
|
|
BF_WriteOneBit( bf, signbit );
|
|
}
|
|
|
|
void BF_WriteBitAngles( sizebuf_t *bf, const float *fa )
|
|
{
|
|
// FIXME: uses WriteBitAngle instead ?
|
|
BF_WriteBitVec3Coord( bf, fa );
|
|
}
|
|
|
|
void BF_WriteChar( sizebuf_t *bf, int val )
|
|
{
|
|
BF_WriteSBitLong( bf, val, sizeof( char ) << 3 );
|
|
}
|
|
|
|
void BF_WriteByte( sizebuf_t *bf, int val )
|
|
{
|
|
BF_WriteUBitLong( bf, val, sizeof( byte ) << 3 );
|
|
}
|
|
|
|
void BF_WriteShort( sizebuf_t *bf, int val )
|
|
{
|
|
BF_WriteSBitLong( bf, val, sizeof(short ) << 3 );
|
|
}
|
|
|
|
void BF_WriteWord( sizebuf_t *bf, int val )
|
|
{
|
|
BF_WriteUBitLong( bf, val, sizeof( word ) << 3 );
|
|
}
|
|
|
|
void BF_WriteLong( sizebuf_t *bf, long val )
|
|
{
|
|
BF_WriteSBitLong( bf, val, sizeof( long ) << 3 );
|
|
}
|
|
|
|
void BF_WriteFloat( sizebuf_t *bf, float val )
|
|
{
|
|
BF_WriteBits( bf, &val, sizeof( val ) << 3 );
|
|
}
|
|
|
|
qboolean BF_WriteBytes( sizebuf_t *bf, const void *pBuf, int nBytes )
|
|
{
|
|
return BF_WriteBits( bf, pBuf, nBytes << 3 );
|
|
}
|
|
|
|
qboolean BF_WriteString( sizebuf_t *bf, const char *pStr )
|
|
{
|
|
if( pStr )
|
|
{
|
|
do
|
|
{
|
|
BF_WriteChar( bf, *pStr );
|
|
pStr++;
|
|
} while( *( pStr - 1 ));
|
|
}
|
|
else BF_WriteChar( bf, 0 );
|
|
|
|
return !bf->bOverflow;
|
|
}
|
|
|
|
int BF_ReadOneBit( sizebuf_t *bf )
|
|
{
|
|
if( !BF_Overflow( bf, 1 ))
|
|
{
|
|
int value = bf->pData[bf->iCurBit >> 3] & (1 << ( bf->iCurBit & 7 ));
|
|
bf->iCurBit++;
|
|
return !!value;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint BF_ReadUBitLong( sizebuf_t *bf, int numbits )
|
|
{
|
|
int idword1;
|
|
uint dword1, ret;
|
|
|
|
if( numbits == 8 )
|
|
{
|
|
int leftBits = BF_GetNumBitsLeft( bf );
|
|
|
|
if( leftBits >= 0 && leftBits < 8 )
|
|
return 0; // end of message
|
|
}
|
|
|
|
if(( bf->iCurBit + numbits ) > bf->nDataBits )
|
|
{
|
|
bf->bOverflow = true;
|
|
bf->iCurBit = bf->nDataBits;
|
|
return 0;
|
|
}
|
|
|
|
ASSERT( numbits > 0 && numbits <= 32 );
|
|
|
|
// Read the current dword.
|
|
idword1 = bf->iCurBit >> 5;
|
|
dword1 = ((uint *)bf->pData)[idword1];
|
|
dword1 >>= ( bf->iCurBit & 31 ); // get the bits we're interested in.
|
|
|
|
bf->iCurBit += numbits;
|
|
ret = dword1;
|
|
|
|
// Does it span this dword?
|
|
if(( bf->iCurBit - 1 ) >> 5 == idword1 )
|
|
{
|
|
if( numbits != 32 )
|
|
ret &= ExtraMasks[numbits];
|
|
}
|
|
else
|
|
{
|
|
int nExtraBits = bf->iCurBit & 31;
|
|
uint dword2 = ((uint *)bf->pData)[idword1+1] & ExtraMasks[nExtraBits];
|
|
|
|
// no need to mask since we hit the end of the dword.
|
|
// shift the second dword's part into the high bits.
|
|
ret |= (dword2 << ( numbits - nExtraBits ));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
float BF_ReadBitFloat( sizebuf_t *bf )
|
|
{
|
|
long val;
|
|
int bit, byte;
|
|
|
|
ASSERT( sizeof( float ) == sizeof( long ));
|
|
ASSERT( sizeof( float ) == 4 );
|
|
|
|
if( BF_Overflow( bf, 32 ))
|
|
return 0.0f;
|
|
|
|
bit = bf->iCurBit & 0x7;
|
|
byte = bf->iCurBit >> 3;
|
|
|
|
val = bf->pData[byte] >> bit;
|
|
val |= ((int)bf->pData[byte + 1]) << ( 8 - bit );
|
|
val |= ((int)bf->pData[byte + 2]) << ( 16 - bit );
|
|
val |= ((int)bf->pData[byte + 3]) << ( 24 - bit );
|
|
|
|
if( bit != 0 )
|
|
val |= ((int)bf->pData[byte + 4]) << ( 32 - bit );
|
|
bf->iCurBit += 32;
|
|
|
|
return *((float *)&val);
|
|
}
|
|
|
|
qboolean BF_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
|
|
{
|
|
byte *pOut = (byte *)pOutData;
|
|
int nBitsLeft = nBits;
|
|
|
|
|
|
// get output dword-aligned.
|
|
while((( dword )pOut & 3) != 0 && nBitsLeft >= 8 )
|
|
{
|
|
*pOut = (byte)BF_ReadUBitLong( bf, 8 );
|
|
++pOut;
|
|
nBitsLeft -= 8;
|
|
}
|
|
|
|
// read dwords.
|
|
while( nBitsLeft >= 32 )
|
|
{
|
|
*((dword *)pOut) = BF_ReadUBitLong( bf, 32 );
|
|
pOut += sizeof( dword );
|
|
nBitsLeft -= 32;
|
|
}
|
|
|
|
// read the remaining bytes.
|
|
while( nBitsLeft >= 8 )
|
|
{
|
|
*pOut = BF_ReadUBitLong( bf, 8 );
|
|
++pOut;
|
|
nBitsLeft -= 8;
|
|
}
|
|
|
|
// read the remaining bits.
|
|
if( nBitsLeft )
|
|
{
|
|
*pOut = BF_ReadUBitLong( bf, nBitsLeft );
|
|
}
|
|
|
|
return !bf->bOverflow;
|
|
}
|
|
|
|
float BF_ReadBitAngle( sizebuf_t *bf, int numbits )
|
|
{
|
|
float fReturn, shift;
|
|
int i;
|
|
|
|
shift = (float)( 1 << numbits );
|
|
|
|
i = BF_ReadUBitLong( bf, numbits );
|
|
fReturn = (float)i * ( 360.0 / shift );
|
|
|
|
// clamp the finale angle
|
|
if( fReturn < -180 ) fReturn += 360;
|
|
else if( fReturn > 180 ) fReturn -= 360;
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
// Append numbits least significant bits from data to the current bit stream
|
|
int BF_ReadSBitLong( sizebuf_t *bf, int numbits )
|
|
{
|
|
int r, sign;
|
|
|
|
r = BF_ReadUBitLong( bf, 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 = BF_ReadOneBit( bf );
|
|
if( sign ) r = -(( 1 << ( numbits - 1 )) - r);
|
|
|
|
return r;
|
|
}
|
|
|
|
uint BF_ReadBitLong( sizebuf_t *bf, int numbits, qboolean bSigned )
|
|
{
|
|
if( bSigned )
|
|
return (uint)BF_ReadSBitLong( bf, numbits );
|
|
return BF_ReadUBitLong( bf, numbits );
|
|
}
|
|
|
|
|
|
// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants)
|
|
float BF_ReadBitCoord( sizebuf_t *bf )
|
|
{
|
|
int intval = 0, fractval = 0, signbit = 0;
|
|
float value = 0.0;
|
|
|
|
// read the required integer and fraction flags
|
|
intval = BF_ReadOneBit( bf );
|
|
fractval = BF_ReadOneBit( bf );
|
|
|
|
// if we got either parse them, otherwise it's a zero.
|
|
if( intval || fractval )
|
|
{
|
|
// read the sign bit
|
|
signbit = BF_ReadOneBit( bf );
|
|
|
|
// 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 = BF_ReadUBitLong( bf, COORD_INTEGER_BITS ) + 1;
|
|
}
|
|
|
|
// if there's a fraction, read it in
|
|
if( fractval )
|
|
{
|
|
fractval = BF_ReadUBitLong( bf, 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;
|
|
}
|
|
|
|
void BF_ReadBitVec3Coord( sizebuf_t *bf, vec3_t 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[0] = fa[1] = fa[2] = 0.0f;
|
|
|
|
xflag = BF_ReadOneBit( bf );
|
|
yflag = BF_ReadOneBit( bf );
|
|
zflag = BF_ReadOneBit( bf );
|
|
|
|
if( xflag ) fa[0] = BF_ReadBitCoord( bf );
|
|
if( yflag ) fa[1] = BF_ReadBitCoord( bf );
|
|
if( zflag ) fa[2] = BF_ReadBitCoord( bf );
|
|
}
|
|
|
|
float BF_ReadBitNormal( sizebuf_t *bf )
|
|
{
|
|
// read the sign bit
|
|
int signbit = BF_ReadOneBit( bf );
|
|
|
|
// read the fractional part
|
|
uint fractval = BF_ReadUBitLong( bf, 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 BF_ReadBitVec3Normal( sizebuf_t *bf, vec3_t fa )
|
|
{
|
|
int xflag = BF_ReadOneBit( bf );
|
|
int yflag = BF_ReadOneBit( bf );
|
|
int znegative;
|
|
float fafafbfb;
|
|
|
|
if( xflag ) fa[0] = BF_ReadBitNormal( bf );
|
|
else fa[0] = 0.0f;
|
|
|
|
if( yflag ) fa[1] = BF_ReadBitNormal( bf );
|
|
else fa[1] = 0.0f;
|
|
|
|
// the first two imply the third (but not its sign)
|
|
znegative = BF_ReadOneBit( bf );
|
|
fafafbfb = fa[0] * fa[0] + fa[1] * fa[1];
|
|
|
|
if( fafafbfb < 1.0f )
|
|
fa[2] = com.sqrt( 1.0f - fafafbfb );
|
|
else fa[2] = 0.0f;
|
|
|
|
if( znegative ) fa[2] = -fa[2];
|
|
}
|
|
|
|
int BF_ReadChar( sizebuf_t *bf )
|
|
{
|
|
return BF_ReadSBitLong( bf, sizeof( char ) << 3 );
|
|
}
|
|
|
|
int BF_ReadByte( sizebuf_t *bf )
|
|
{
|
|
return BF_ReadUBitLong( bf, sizeof( byte ) << 3 );
|
|
}
|
|
|
|
int BF_ReadShort( sizebuf_t *bf )
|
|
{
|
|
return BF_ReadSBitLong( bf, sizeof( short ) << 3 );
|
|
}
|
|
|
|
int BF_ReadWord( sizebuf_t *bf )
|
|
{
|
|
return BF_ReadUBitLong( bf, sizeof( word ) << 3 );
|
|
}
|
|
|
|
long BF_ReadLong( sizebuf_t *bf )
|
|
{
|
|
return BF_ReadSBitLong( bf, sizeof( long ) << 3 );
|
|
}
|
|
|
|
float BF_ReadFloat( sizebuf_t *bf )
|
|
{
|
|
float ret;
|
|
ASSERT( sizeof( ret ) == 4 );
|
|
|
|
BF_ReadBits( bf, &ret, 32 );
|
|
|
|
return ret;
|
|
}
|
|
|
|
qboolean BF_ReadBytes( sizebuf_t *bf, void *pOut, int nBytes )
|
|
{
|
|
return BF_ReadBits( bf, pOut, nBytes << 3 );
|
|
}
|
|
|
|
char *BF_ReadStringExt( sizebuf_t *bf, qboolean bLine )
|
|
{
|
|
static char string[MAX_SYSPATH];
|
|
int l = 0, c;
|
|
|
|
do
|
|
{
|
|
// use BF_ReadByte so -1 is out of bounds
|
|
c = BF_ReadByte( bf );
|
|
|
|
if( c == 0 ) break;
|
|
else if( bLine && c == '\n' )
|
|
break;
|
|
|
|
// translate all fmt spec to avoid crash bugs
|
|
if( c == '%' ) c = '.';
|
|
|
|
string[l] = c;
|
|
l++;
|
|
} while( l < sizeof( string ) - 1 );
|
|
string[l] = 0; // terminator
|
|
|
|
return string;
|
|
}
|
|
|
|
void BF_ExciseBits( sizebuf_t *bf, int startbit, int bitstoremove )
|
|
{
|
|
int i, endbit = startbit + bitstoremove;
|
|
int remaining_to_end = bf->nDataBits - endbit;
|
|
sizebuf_t temp;
|
|
|
|
BF_StartWriting( &temp, bf->pData, bf->nDataBits << 3, startbit, -1 );
|
|
BF_SeekToBit( bf, endbit );
|
|
|
|
for( i = 0; i < remaining_to_end; i++ )
|
|
{
|
|
BF_WriteOneBit( &temp, BF_ReadOneBit( bf ));
|
|
}
|
|
|
|
BF_SeekToBit( bf, startbit );
|
|
bf->nDataBits -= bitstoremove;
|
|
} |