DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Serializer.h (19295B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 #ifndef __SERIALIZER_H__
     29 #define __SERIALIZER_H__
     30 
     31 #define SERIALIZE_BOOL( ser, x )			( ( x ) = ser.SerializeBoolNonRef( x ) )
     32 #define SERIALIZE_ENUM( ser, x, type, max ) ( ( x ) = (type)ser.SerializeUMaxNonRef( x, max ) )
     33 #define SERIALIZE_CVAR_FLOAT( ser, cvar )	{ float a = cvar.GetFloat(); ser.Serialize( a ); cvar.SetFloat( a ); }
     34 #define SERIALIZE_CVAR_INT( ser, cvar )		{ int a = cvar.GetInteger(); ser.Serialize( a ); cvar.SetInteger( a ); }
     35 #define SERIALIZE_CVAR_BOOL( ser, cvar )	{ bool a = cvar.GetBool(); SERIALIZE_BOOL( ser, a ); cvar.SetBool( a ); }
     36 
     37 #define SERIALIZE_MATX( ser, var )				\
     38 {												\
     39 	int rows = var.GetNumRows();				\
     40 	int cols = var.GetNumColumns();				\
     41 	ser.Serialize( rows );						\
     42 	ser.Serialize( cols );						\
     43 	if ( ser.IsReading() ) {					\
     44 		var.SetSize( rows, cols );				\
     45 	}											\
     46 	for ( int y = 0; y < rows; y++ ) {			\
     47 		for ( int x = 0; x < rows; x++ ) {		\
     48 			ser.Serialize( var[x][y] );			\
     49 		}										\
     50 	}											\
     51 }												\
     52 
     53 #define SERIALIZE_VECX( ser, var )				\
     54 {												\
     55 	int size = var.GetSize();					\
     56 	ser.Serialize( size );						\
     57 	if ( ser.IsReading() ) {					\
     58 		var.SetSize( size );					\
     59 	}											\
     60 	for ( int x = 0; x < size; x++ ) {			\
     61 		ser.Serialize( var[x] );				\
     62 	}											\
     63 }												\
     64 
     65 #define SERIALIZE_JOINT( ser, var )				\
     66 {												\
     67 	uint16 jointIndex = ( var == NULL_JOINT_INDEX ) ? 65535 : var;	\
     68 	ser.Serialize( jointIndex );					\
     69 	var = ( jointIndex == 65535 ) ? NULL_JOINT_INDEX : (jointIndex_t)jointIndex; \
     70 }												\
     71 
     72 //#define ENABLE_SERIALIZE_CHECKPOINTS
     73 //#define SERIALIZE_SANITYCHECK
     74 //#define SERIALIZE_NO_QUANT
     75 
     76 #define SERIALIZE_CHECKPOINT( ser )			\
     77 	ser.SerializeCheckpoint( __FILE__, __LINE__ );
     78 
     79 /*
     80 ========================
     81 idSerializer
     82 ========================
     83 */
     84 class idSerializer {
     85 public:
     86 	idSerializer( idBitMsg & msg_, bool writing_) : msg( &msg_ ), writing( writing_ )
     87 #ifdef SERIALIZE_SANITYCHECK
     88 	,magic( 0 ) 
     89 #endif
     90 	{ }
     91 
     92 	bool	IsReading() { return !writing; }
     93 	bool	IsWriting() { return writing; }
     94 
     95 	// SerializeRange - minSize through maxSize inclusive of all possible values
     96 	void	SerializeRange( int & value, int minSize, int maxSize ) {	// Supports signed types
     97 		SanityCheck();
     98 		if ( writing ) {
     99 			msg->WriteBits( value - minSize, idMath::BitsForInteger( maxSize-minSize ) );
    100 		} else {
    101 			value = minSize + msg->ReadBits( idMath::BitsForInteger( maxSize-minSize ) );
    102 		}
    103 		assert( value >= minSize && value <= maxSize );
    104 	}
    105 
    106 	// SerializeUMax - maxSize inclusive, unsigned
    107 	void	SerializeUMax( int & value, int maxSize ) {					// Unsigned only
    108 		SanityCheck();
    109 		if ( writing ) {
    110 			msg->WriteBits( value, idMath::BitsForInteger( maxSize ) );
    111 		} else {
    112 			value = msg->ReadBits( idMath::BitsForInteger( maxSize ) );
    113 		}
    114 		assert( value <= maxSize );
    115 	}
    116 
    117 	// SerializeUMaxNonRef - maxSize inclusive, unsigned, no reference
    118 	int	SerializeUMaxNonRef( int value, int maxSize ) {					// Unsigned only
    119 		SanityCheck();
    120 		if ( writing ) {
    121 			msg->WriteBits(value, idMath::BitsForInteger( maxSize ) );
    122 		} else {
    123 			value = msg->ReadBits( idMath::BitsForInteger( maxSize ) );
    124 		}
    125 		assert( value <= maxSize );
    126 		return value;
    127 	}
    128 
    129 	//void SerializeBitMsg( idBitMsg & inOutMsg, int numBytes ) { SanityCheck(); if ( writing ) { msg->WriteBitMsg( inOutMsg, numBytes ); } else { msg->ReadBitMsg( inOutMsg, numBytes ); } }
    130 
    131 	// this is still needed to compile Rage code
    132 	void	SerializeBytes( void * bytes, int numBytes ) { SanityCheck(); for ( int i = 0 ; i < numBytes ; i++ ) { Serialize( ((uint8 *)bytes)[i] ); } };
    133 
    134 	bool	SerializeBoolNonRef( bool value )	{ SanityCheck(); if ( writing ) { msg->WriteBool(value); }		else { value = msg->ReadBool(); } return value; }		// We return a value so we can support bit fields (can't pass by reference)
    135 	
    136 
    137 #ifdef SERIALIZE_NO_QUANT
    138 	template< int _max_, int _numBits_ >
    139 	void	SerializeQ( idVec3 & value ) { Serialize( value ); }
    140 	template< int _max_, int _numBits_ >
    141 	void	SerializeQ( float & value ) { Serialize( value ); }
    142 	template< int _max_, int _numBits_ >
    143 	void	SerializeUQ( float & value ) { Serialize( value ); }
    144 	void	SerializeQ( idMat3 & axis, int bits = 15 ) { Serialize( axis ); }
    145 #else
    146 	// SerializeQ - Quantizes a float to a variable number of bits (assumes signed, uses simple quantization)
    147 	template< int _max_, int _numBits_ >
    148 	void	SerializeQ( idVec3 & value ) { SanityCheck(); if ( writing ) { msg->WriteQuantizedVector< idVec3, _max_, _numBits_ >( value ); }	else { msg->ReadQuantizedVector< idVec3, _max_, _numBits_ >( value ); } }
    149 	template< int _max_, int _numBits_ >
    150 	void	SerializeQ( float & value ) { SanityCheck(); if ( writing ) { msg->WriteQuantizedFloat< _max_, _numBits_ >( value ); }		else { value = msg->ReadQuantizedFloat< _max_, _numBits_ >(); } }
    151 	template< int _max_, int _numBits_ >
    152 	void	SerializeUQ( float & value ) { SanityCheck(); if ( writing ) { msg->WriteQuantizedUFloat< _max_, _numBits_ >( value ); }	else { value = msg->ReadQuantizedUFloat< _max_, _numBits_ >(); } }
    153 	void	SerializeQ( idMat3 & axis, int bits = 15 );		// Default to 15 bits per component, which has almost unnoticeable quantization
    154 #endif
    155 
    156 	void	Serialize( idMat3 & axis);			// Raw 3x3 matrix serialize
    157 	void	SerializeC( idMat3 & axis);			// Uses compressed quaternion
    158 	
    159 	template< typename _type_ >  
    160 	void	SerializeListElement( const idList<_type_* > & list, const _type_ *&element );
    161 
    162 	void	SerializePacked(int & original);
    163 	void	SerializeSPacked(int & original);
    164 
    165 	void	SerializeString( char * s, int bufferSize )	{ SanityCheck(); if ( writing ) { msg->WriteString(s); } else { msg->ReadString( s, bufferSize ); } }
    166 	//void	SerializeString( idAtomicString & s )		{ SanityCheck(); if ( writing ) { msg->WriteString(s); } else { idStr temp; msg->ReadString( temp ); s.Set( temp ); } }
    167 	void	SerializeString( idStr & s )				{ SanityCheck(); if ( writing ) { msg->WriteString(s); } else { msg->ReadString( s ); } }
    168 	//void	SerializeString( idStrId & s )				{ SanityCheck(); if ( writing ) { msg->WriteString(s.GetKey()); } else { idStr key; msg->ReadString( key ); s.Set( key );} }
    169 
    170 	void	SerializeDelta( int32 & value, const int32 & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaLong( base, value ); } else { value = msg->ReadDeltaLong( base ); } }
    171 	void	SerializeDelta( int16 & value, const int16 & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaShort( base, value ); } else { value = msg->ReadDeltaShort( base ); } }
    172 	void	SerializeDelta( int8 & value, const int8 & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaChar( base, value ); } else { value = msg->ReadDeltaChar( base ); } }
    173 
    174 	void	SerializeDelta( uint16 & value, const uint16 & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaUShort( base, value ); } else { value = msg->ReadDeltaUShort( base ); } }
    175 	void	SerializeDelta( uint8 & value, const uint8 & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaByte( base, value ); } else { value = msg->ReadDeltaByte( base ); } }
    176 
    177 	void	SerializeDelta( float & value, const float & base ) { SanityCheck(); if ( writing ) { msg->WriteDeltaFloat( base, value ); } else { value = msg->ReadDeltaFloat( base ); } }
    178 
    179 
    180 	// Common types, no compression
    181 	void	Serialize( int64 & value )		{ SanityCheck(); if ( writing ) { msg->WriteLongLong(value); }		else { value = msg->ReadLongLong(); } }
    182 	void	Serialize( uint64 & value )		{ SanityCheck(); if ( writing ) { msg->WriteLongLong(value); }		else { value = msg->ReadLongLong(); } }
    183 	void	Serialize( int32 & value )		{ SanityCheck(); if ( writing ) { msg->WriteLong(value); }			else { value = msg->ReadLong(); } }
    184 	void	Serialize( uint32 & value )		{ SanityCheck(); if ( writing ) { msg->WriteLong(value); }			else { value = msg->ReadLong(); } }
    185 	void	Serialize( int16 & value )		{ SanityCheck(); if ( writing ) { msg->WriteShort(value); }			else { value = msg->ReadShort(); } }
    186 	void	Serialize( uint16 & value )		{ SanityCheck(); if ( writing ) { msg->WriteUShort(value); }		else { value = msg->ReadUShort(); } }
    187 	void	Serialize( uint8 & value )		{ SanityCheck(); if ( writing ) { msg->WriteByte(value); }			else { value = msg->ReadByte(); } }
    188 	void	Serialize( int8 & value )		{ SanityCheck(); if ( writing ) { msg->WriteChar(value); }			else { value = msg->ReadChar(); } }
    189 	void	Serialize( bool & value )		{ SanityCheck(); if ( writing ) { msg->WriteByte(value?1:0); }		else { value = msg->ReadByte() != 0; } }
    190 	void	Serialize( float & value )		{ SanityCheck(); if ( writing ) { msg->WriteFloat(value); }			else { value = msg->ReadFloat(); } }
    191 	void	Serialize( idRandom2 & value )	{ SanityCheck(); if ( writing ) { msg->WriteLong(value.GetSeed()); } else { value.SetSeed( msg->ReadLong() ); } }
    192 	void	Serialize( idVec3 & value )		{ SanityCheck(); if ( writing ) { msg->WriteVectorFloat(value); }	else { msg->ReadVectorFloat(value); } }
    193 	void	Serialize( idVec2 & value )		{ SanityCheck(); if ( writing ) { msg->WriteVectorFloat(value); }	else { msg->ReadVectorFloat(value); } }
    194 	void	Serialize( idVec6 & value )		{ SanityCheck(); if ( writing ) { msg->WriteVectorFloat(value); }	else { msg->ReadVectorFloat(value); } }
    195 	void	Serialize( idVec4 & value )		{ SanityCheck(); if ( writing ) { msg->WriteVectorFloat(value); }	else { msg->ReadVectorFloat(value); } }
    196 
    197 	// serialize an angle, normalized to between 0 to 360 and quantized to 16 bits
    198 	void	SerializeAngle( float & value ) {
    199 				SanityCheck(); 
    200 				if ( writing ) {
    201 					float nAngle = idMath::AngleNormalize360( value );
    202 					assert( nAngle >= 0.0f ); // should never get a negative angle
    203 					uint16 sAngle = nAngle * ( 65536.0f / 360.0f );
    204 					msg->WriteUShort( sAngle );
    205 				} else {
    206 					uint16 sAngle = msg->ReadUShort();
    207 					value = sAngle * ( 360.0f / 65536.0f );
    208 				}
    209 
    210 			}
    211 
    212 	//void	Serialize( degrees_t & value )	{ 
    213 	//			SanityCheck(); 
    214 	//			float angle = value.Get();
    215 	//			Serialize( angle );
    216 	//			value.Set( angle );
    217 	//		}
    218 	//void	SerializeAngle( degrees_t & value )	{ 
    219 	//			SanityCheck(); 
    220 	//			float angle = value.Get();
    221 	//			SerializeAngle( angle );
    222 	//			value.Set( angle );
    223 	//		}
    224 	//void	Serialize( radians_t & value ) { 
    225 	//			SanityCheck();
    226 	//			// convert to degrees
    227 	//			degrees_t d( value.Get() * idMath::M_RAD2DEG );
    228 	//			Serialize( d );
    229 	//			if ( !writing ) {
    230 	//				// if reading, get the value we read in degrees and convert back to radians
    231 	//				value.Set( d.Get() * idMath::M_DEG2RAD );
    232 	//			}
    233 	//		}
    234 	//void	SerializeAngle( radians_t & value ) { 
    235 	//			SanityCheck();
    236 	//			// convert to degrees
    237 	//			degrees_t d( value.Get() * idMath::M_RAD2DEG );
    238 	//			// serialize as normalized degrees between 0 - 360
    239 	//			SerializeAngle( d );
    240 	//			if ( !writing ) {
    241 	//				// if reading, get the value we read in degrees and convert back to radians
    242 	//				value.Set( d.Get() * idMath::M_DEG2RAD );
    243 	//			}
    244 	//		}
    245 	//
    246 	//void	Serialize( idColor & value ) {
    247 	//	Serialize( value.r );
    248 	//	Serialize( value.g );
    249 	//	Serialize( value.b );
    250 	//	Serialize( value.a );
    251 	//}
    252 	
    253 	void	SanityCheck() {
    254 #ifdef SERIALIZE_SANITYCHECK
    255 		if ( writing ) {
    256 			msg->WriteUShort( 0xCCCC );
    257 			msg->WriteUShort( magic );
    258 		} else {
    259 			int cccc = msg->ReadUShort();
    260 			int m = msg->ReadUShort();
    261 			assert( cccc == 0xCCCC );
    262 			assert( m == magic );
    263 			// For release builds
    264 			if ( cccc != 0xCCCC ) {
    265 				idLib::Error( "idSerializer::SanityCheck - cccc != 0xCCCC" );
    266 			}
    267 			if ( m != magic ) {
    268 				idLib::Error( "idSerializer::SanityCheck - m != magic" );
    269 			}
    270 		}
    271 		magic++;
    272 #endif
    273 	}
    274 
    275 	void SerializeCheckpoint( const char * file, int line ) {
    276 #ifdef ENABLE_SERIALIZE_CHECKPOINTS
    277 		const uint32 tagValue = 0xABADF00D;
    278 		uint32 tag = tagValue;
    279 		Serialize( tag );
    280 		if ( tag != tagValue ) {
    281 			idLib::Error( "SERIALIZE_CHECKPOINT: tag != tagValue (file: %s - line: %i)", file, line );
    282 		}
    283 #endif
    284 	}
    285 
    286 	idBitMsg &	GetMsg() { return *msg; }
    287 
    288 private:
    289 	bool		writing;
    290 	idBitMsg *	msg;
    291 #ifdef SERIALIZE_SANITYCHECK
    292 	int			magic;
    293 #endif
    294 };
    295 
    296 class idSerializerScopedBlock {
    297 public:
    298 	idSerializerScopedBlock( idSerializer &ser_, int maxSizeBytes_ ) {
    299 		ser = &ser_;
    300 		maxSizeBytes = maxSizeBytes_;
    301 	
    302 		startByte = ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize();
    303 		startWriteBits = ser->GetMsg().GetWriteBit();
    304 	}
    305 
    306 	~idSerializerScopedBlock() {
    307 	
    308 		// Serialize remaining bits
    309 		while ( ser->GetMsg().GetWriteBit() != startWriteBits ) {
    310 			ser->SerializeBoolNonRef( false );
    311 		}
    312 	
    313 		// Verify we didn't go over
    314 		int endByte = ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize();
    315 		int sizeBytes = endByte - startByte;
    316 		if ( !verify( sizeBytes <= maxSizeBytes ) ) {
    317 			idLib::Warning( "idSerializerScopedBlock went over maxSize (%d > %d)", sizeBytes, maxSizeBytes );
    318 			return;
    319 		}
    320 
    321 		// Serialize remaining bytes
    322 		uint8 b=0;
    323 		while ( sizeBytes < maxSizeBytes ) {
    324 			ser->Serialize( b );
    325 			sizeBytes++;
    326 		}
    327 
    328 		int finalSize = ( ( ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize() ) - startByte );
    329 		verify( maxSizeBytes == finalSize );
    330 	}
    331 
    332 private:
    333 	idSerializer * ser;
    334 	int maxSizeBytes;
    335 	
    336 	int startByte;
    337 	int startWriteBits;
    338 };
    339 
    340 
    341 
    342 
    343 /*
    344 ========================
    345 idSerializer::SerializeQ
    346 ========================
    347 */
    348 #ifndef SERIALIZE_NO_QUANT
    349 ID_INLINE void idSerializer::SerializeQ( idMat3 &axis, int bits ) {
    350 	SanityCheck();
    351 
    352 	const float scale = ( ( 1 << ( bits - 1 ) ) - 1 );
    353 	if ( IsWriting() ) {
    354 		idQuat quat = axis.ToQuat();
    355 
    356 		int maxIndex = 0;
    357 		for ( unsigned int i = 1; i < 4; i++ ) {
    358 			if ( idMath::Fabs( quat[i] ) > idMath::Fabs( quat[maxIndex] ) ) {
    359 				maxIndex = i;
    360 			}
    361 		}
    362 
    363 		msg->WriteBits( maxIndex, 2 );
    364 
    365 		idVec3 out;
    366 
    367 		if ( quat[maxIndex] < 0.0f ) {
    368 			out.x = -quat[( maxIndex + 1 ) & 3];
    369 			out.y = -quat[( maxIndex + 2 ) & 3];
    370 			out.z = -quat[( maxIndex + 3 ) & 3];
    371 		} else {
    372 			out.x = quat[( maxIndex + 1 ) & 3];
    373 			out.y = quat[( maxIndex + 2 ) & 3];
    374 			out.z = quat[( maxIndex + 3 ) & 3];
    375 		}
    376 		msg->WriteBits( idMath::Ftoi( out.x * scale ), -bits);
    377 		msg->WriteBits( idMath::Ftoi( out.y * scale ), -bits);
    378 		msg->WriteBits( idMath::Ftoi( out.z * scale ), -bits);
    379 	
    380 	} else if ( IsReading() ) {
    381 		idQuat quat;
    382 		idVec3 in;
    383 
    384 		int maxIndex = msg->ReadBits(2);
    385 
    386 		in.x = (float)msg->ReadBits(-bits) / scale;
    387 		in.y = (float)msg->ReadBits(-bits) / scale;
    388 		in.z = (float)msg->ReadBits(-bits) / scale;
    389 
    390 		quat[( maxIndex + 1 ) & 3] = in.x;
    391 		quat[( maxIndex + 2 ) & 3] = in.y;
    392 		quat[( maxIndex + 3 ) & 3] = in.z;
    393 
    394 		quat[maxIndex] = idMath::Sqrt( idMath::Fabs( 1.0f - in.x * in.x - in.y * in.y - in.z * in.z ) );
    395 
    396 		axis = quat.ToMat3();
    397 	}
    398 }
    399 #endif
    400 
    401 /*
    402 ========================
    403 idSerializer::Serialize
    404 ========================
    405 */
    406 ID_INLINE void idSerializer::Serialize( idMat3 & axis ) {
    407 	SanityCheck();
    408 
    409 	Serialize( axis[0] );
    410 	Serialize( axis[1] );
    411 	Serialize( axis[2] );
    412 }
    413 
    414 /*
    415 ========================
    416 idSerializer::SerializeC
    417 ========================
    418 */
    419 ID_INLINE void idSerializer::SerializeC( idMat3 & axis ) {
    420 	SanityCheck();
    421 
    422 	if ( IsWriting() ) {
    423 		idCQuat cquat = axis.ToCQuat();
    424 
    425 		Serialize( cquat.x );
    426 		Serialize( cquat.y );
    427 		Serialize( cquat.z );
    428 	} else if ( IsReading() ) {
    429 		idCQuat cquat;
    430 
    431 		Serialize( cquat.x );
    432 		Serialize( cquat.y );
    433 		Serialize( cquat.z );
    434 
    435 		axis = cquat.ToMat3();
    436 	}
    437 }
    438 
    439 /*
    440 ========================
    441 idSerializer::SerializeListElement
    442 ========================
    443 */
    444 template< typename _type_ >  
    445 ID_INLINE void idSerializer::SerializeListElement( const idList<_type_* > & list, const _type_ *&element ) {
    446 	SanityCheck();
    447 
    448 	if ( IsWriting() ) {
    449 		int index = list.FindIndex( const_cast<_type_ *>(element) );
    450 		assert( index >= 0 );
    451 		SerializePacked( index );
    452 	} else if ( IsReading() ) {
    453 		int index = 0;
    454 		SerializePacked( index );
    455 		element = list[index];
    456 	}
    457 }
    458 
    459 /*
    460 ========================
    461 idSerializer::SerializePacked
    462 Writes out 7 bits at a time, using every 8th bit to signify more bits exist
    463 
    464 NOTE - Signed values work with this function, but take up more bytes
    465 Use SerializeSPacked if you anticipate lots of negative values 
    466 ========================
    467 */
    468 ID_INLINE void idSerializer::SerializePacked(int & original) {
    469 	SanityCheck();
    470 
    471 	if ( IsWriting() ) {
    472 		uint32 value = original;
    473 
    474 		while ( true ) {
    475 			uint8 byte = value & 0x7F;
    476 			value >>= 7;
    477 			byte |= value ? 0x80 : 0;
    478 			msg->WriteByte( byte );		// Emit byte
    479 			if ( value == 0 ) {
    480 				break;
    481 			}
    482 		}
    483 	} else {
    484 		uint8 byte = 0x80;
    485 		uint32 value = 0;
    486 		int32 shift = 0;
    487 
    488 		while ( byte & 0x80 && shift < 32 ) {
    489 			byte = msg->ReadByte();
    490 			value |= (byte & 0x7F) << shift;
    491 			shift += 7;
    492 		}
    493 
    494 		original = value;
    495 	}
    496 }
    497 
    498 /*
    499 ========================
    500 idSerializer::SerializeSPacked
    501 Writes out 7 bits at a time, using every 8th bit to signify more bits exist
    502 
    503 NOTE - An extra bit of the first byte is used to store the sign
    504 (this function supports negative values, but will use 2 bytes for values greater than 63)
    505 ========================
    506 */
    507 ID_INLINE void idSerializer::SerializeSPacked(int & value) {
    508 	SanityCheck();
    509 
    510 	if ( IsWriting() ) {
    511 
    512 		uint32 uvalue = idMath::Abs( value );
    513 
    514 		// Write the first byte specifically to handle the sign bit
    515 		uint8 byte = uvalue & 0x3f;
    516 		byte |= value < 0 ? 0x40 : 0;
    517 		uvalue >>= 6;
    518 		byte |= uvalue > 0 ? 0x80 : 0;
    519 
    520 		msg->WriteByte( byte );
    521 
    522 		while ( uvalue > 0 ) {
    523 			uint8 byte2 = uvalue & 0x7F;
    524 			uvalue >>= 7;
    525 			byte2 |= uvalue ? 0x80 : 0;
    526 			msg->WriteByte( byte2 );		// Emit byte
    527 		}
    528 	} else {
    529 		// Load the first byte specifically to handle the sign bit
    530 		uint8 byte		= msg->ReadByte();
    531 		uint32 uvalue	= byte & 0x3f;
    532 		bool sgn		= (byte & 0x40) ? true : false;
    533 		int32 shift		= 6;
    534 		
    535 		while ( byte & 0x80 && shift < 32 ) {
    536 			byte = msg->ReadByte();		// Read byte
    537 			uvalue |= (byte & 0x7F) << shift;
    538 			shift += 7;
    539 		}
    540 
    541 		value = sgn ? -((int)uvalue) : uvalue;
    542 	}
    543 }
    544 
    545 #endif
    546 
    547 
    548 
    549