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