mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-11 13:11:47 +00:00
d949bc9410
many of the warnings -Wreorder and #includes with invalid path because of case-errors (windows may not care, but linux does)
937 lines
20 KiB
C++
937 lines
20 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
#ifndef __SERIALIZER_H__
|
|
#define __SERIALIZER_H__
|
|
|
|
#define SERIALIZE_BOOL( ser, x ) ( ( x ) = ser.SerializeBoolNonRef( x ) )
|
|
#define SERIALIZE_ENUM( ser, x, type, max ) ( ( x ) = (type)ser.SerializeUMaxNonRef( x, max ) )
|
|
#define SERIALIZE_CVAR_FLOAT( ser, cvar ) { float a = cvar.GetFloat(); ser.Serialize( a ); cvar.SetFloat( a ); }
|
|
#define SERIALIZE_CVAR_INT( ser, cvar ) { int a = cvar.GetInteger(); ser.Serialize( a ); cvar.SetInteger( a ); }
|
|
#define SERIALIZE_CVAR_BOOL( ser, cvar ) { bool a = cvar.GetBool(); SERIALIZE_BOOL( ser, a ); cvar.SetBool( a ); }
|
|
|
|
#define SERIALIZE_MATX( ser, var ) \
|
|
{ \
|
|
int rows = var.GetNumRows(); \
|
|
int cols = var.GetNumColumns(); \
|
|
ser.Serialize( rows ); \
|
|
ser.Serialize( cols ); \
|
|
if ( ser.IsReading() ) { \
|
|
var.SetSize( rows, cols ); \
|
|
} \
|
|
for ( int y = 0; y < rows; y++ ) { \
|
|
for ( int x = 0; x < rows; x++ ) { \
|
|
ser.Serialize( var[x][y] ); \
|
|
} \
|
|
} \
|
|
} \
|
|
|
|
#define SERIALIZE_VECX( ser, var ) \
|
|
{ \
|
|
int size = var.GetSize(); \
|
|
ser.Serialize( size ); \
|
|
if ( ser.IsReading() ) { \
|
|
var.SetSize( size ); \
|
|
} \
|
|
for ( int x = 0; x < size; x++ ) { \
|
|
ser.Serialize( var[x] ); \
|
|
} \
|
|
} \
|
|
|
|
#define SERIALIZE_JOINT( ser, var ) \
|
|
{ \
|
|
uint16 jointIndex = ( var == NULL_JOINT_INDEX ) ? 65535 : var; \
|
|
ser.Serialize( jointIndex ); \
|
|
var = ( jointIndex == 65535 ) ? NULL_JOINT_INDEX : (jointIndex_t)jointIndex; \
|
|
} \
|
|
|
|
//#define ENABLE_SERIALIZE_CHECKPOINTS
|
|
//#define SERIALIZE_SANITYCHECK
|
|
//#define SERIALIZE_NO_QUANT
|
|
|
|
#define SERIALIZE_CHECKPOINT( ser ) \
|
|
ser.SerializeCheckpoint( __FILE__, __LINE__ );
|
|
|
|
/*
|
|
========================
|
|
idSerializer
|
|
========================
|
|
*/
|
|
class idSerializer
|
|
{
|
|
public:
|
|
idSerializer( idBitMsg& msg_, bool writing_ ) : writing( writing_ ), msg( &msg_ )
|
|
#ifdef SERIALIZE_SANITYCHECK
|
|
, magic( 0 )
|
|
#endif
|
|
{ }
|
|
|
|
bool IsReading()
|
|
{
|
|
return !writing;
|
|
}
|
|
bool IsWriting()
|
|
{
|
|
return writing;
|
|
}
|
|
|
|
// SerializeRange - minSize through maxSize inclusive of all possible values
|
|
void SerializeRange( int& value, int minSize, int maxSize ) // Supports signed types
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteBits( value - minSize, idMath::BitsForInteger( maxSize - minSize ) );
|
|
}
|
|
else
|
|
{
|
|
value = minSize + msg->ReadBits( idMath::BitsForInteger( maxSize - minSize ) );
|
|
}
|
|
assert( value >= minSize && value <= maxSize );
|
|
}
|
|
|
|
// SerializeUMax - maxSize inclusive, unsigned
|
|
void SerializeUMax( int& value, int maxSize ) // Unsigned only
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteBits( value, idMath::BitsForInteger( maxSize ) );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadBits( idMath::BitsForInteger( maxSize ) );
|
|
}
|
|
assert( value <= maxSize );
|
|
}
|
|
|
|
// SerializeUMaxNonRef - maxSize inclusive, unsigned, no reference
|
|
int SerializeUMaxNonRef( int value, int maxSize ) // Unsigned only
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteBits( value, idMath::BitsForInteger( maxSize ) );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadBits( idMath::BitsForInteger( maxSize ) );
|
|
}
|
|
assert( value <= maxSize );
|
|
return value;
|
|
}
|
|
|
|
//void SerializeBitMsg( idBitMsg & inOutMsg, int numBytes ) { SanityCheck(); if ( writing ) { msg->WriteBitMsg( inOutMsg, numBytes ); } else { msg->ReadBitMsg( inOutMsg, numBytes ); } }
|
|
|
|
// this is still needed to compile Rage code
|
|
void SerializeBytes( void* bytes, int numBytes )
|
|
{
|
|
SanityCheck();
|
|
for( int i = 0 ; i < numBytes ; i++ )
|
|
{
|
|
Serialize( ( ( uint8* )bytes )[i] );
|
|
}
|
|
};
|
|
|
|
bool SerializeBoolNonRef( bool value )
|
|
{
|
|
SanityCheck(); // We return a value so we can support bit fields (can't pass by reference)
|
|
if( writing )
|
|
{
|
|
msg->WriteBool( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadBool();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
#ifdef SERIALIZE_NO_QUANT
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeQ( idVec3& value )
|
|
{
|
|
Serialize( value );
|
|
}
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeQ( float& value )
|
|
{
|
|
Serialize( value );
|
|
}
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeUQ( float& value )
|
|
{
|
|
Serialize( value );
|
|
}
|
|
void SerializeQ( idMat3& axis, int bits = 15 )
|
|
{
|
|
Serialize( axis );
|
|
}
|
|
#else
|
|
// SerializeQ - Quantizes a float to a variable number of bits (assumes signed, uses simple quantization)
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeQ( idVec3& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteQuantizedVector< idVec3, _max_, _numBits_ >( value );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadQuantizedVector< idVec3, _max_, _numBits_ >( value );
|
|
}
|
|
}
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeQ( float& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteQuantizedFloat< _max_, _numBits_ >( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadQuantizedFloat< _max_, _numBits_ >();
|
|
}
|
|
}
|
|
template< int _max_, int _numBits_ >
|
|
void SerializeUQ( float& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteQuantizedUFloat< _max_, _numBits_ >( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadQuantizedUFloat< _max_, _numBits_ >();
|
|
}
|
|
}
|
|
void SerializeQ( idMat3& axis, int bits = 15 ); // Default to 15 bits per component, which has almost unnoticeable quantization
|
|
#endif
|
|
|
|
void Serialize( idMat3& axis ); // Raw 3x3 matrix serialize
|
|
void SerializeC( idMat3& axis ); // Uses compressed quaternion
|
|
|
|
template< typename _type_ >
|
|
void SerializeListElement( const idList<_type_* >& list, const _type_*& element );
|
|
|
|
void SerializePacked( int& original );
|
|
void SerializeSPacked( int& original );
|
|
|
|
void SerializeString( char* s, int bufferSize )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteString( s );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadString( s, bufferSize );
|
|
}
|
|
}
|
|
//void SerializeString( idAtomicString & s ) { SanityCheck(); if ( writing ) { msg->WriteString(s); } else { idStr temp; msg->ReadString( temp ); s.Set( temp ); } }
|
|
void SerializeString( idStr& s )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteString( s );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadString( s );
|
|
}
|
|
}
|
|
//void SerializeString( idStrId & s ) { SanityCheck(); if ( writing ) { msg->WriteString(s.GetKey()); } else { idStr key; msg->ReadString( key ); s.Set( key );} }
|
|
|
|
void SerializeDelta( int32& value, const int32& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaLong( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaLong( base );
|
|
}
|
|
}
|
|
void SerializeDelta( int16& value, const int16& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaShort( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaShort( base );
|
|
}
|
|
}
|
|
void SerializeDelta( int8& value, const int8& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaChar( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaChar( base );
|
|
}
|
|
}
|
|
|
|
void SerializeDelta( uint16& value, const uint16& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaUShort( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaUShort( base );
|
|
}
|
|
}
|
|
void SerializeDelta( uint8& value, const uint8& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaByte( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaByte( base );
|
|
}
|
|
}
|
|
|
|
void SerializeDelta( float& value, const float& base )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteDeltaFloat( base, value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadDeltaFloat( base );
|
|
}
|
|
}
|
|
|
|
|
|
// Common types, no compression
|
|
void Serialize( int64& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteLongLong( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadLongLong();
|
|
}
|
|
}
|
|
void Serialize( uint64& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteLongLong( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadLongLong();
|
|
}
|
|
}
|
|
void Serialize( int32& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteLong( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadLong();
|
|
}
|
|
}
|
|
void Serialize( uint32& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteLong( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadLong();
|
|
}
|
|
}
|
|
void Serialize( int16& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteShort( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadShort();
|
|
}
|
|
}
|
|
void Serialize( uint16& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteUShort( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadUShort();
|
|
}
|
|
}
|
|
void Serialize( uint8& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteByte( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadByte();
|
|
}
|
|
}
|
|
void Serialize( int8& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteChar( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadChar();
|
|
}
|
|
}
|
|
void Serialize( bool& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteByte( value ? 1 : 0 );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadByte() != 0;
|
|
}
|
|
}
|
|
void Serialize( float& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteFloat( value );
|
|
}
|
|
else
|
|
{
|
|
value = msg->ReadFloat();
|
|
}
|
|
}
|
|
void Serialize( idRandom2& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteLong( value.GetSeed() );
|
|
}
|
|
else
|
|
{
|
|
value.SetSeed( msg->ReadLong() );
|
|
}
|
|
}
|
|
void Serialize( idVec3& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteVectorFloat( value );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadVectorFloat( value );
|
|
}
|
|
}
|
|
void Serialize( idVec2& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteVectorFloat( value );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadVectorFloat( value );
|
|
}
|
|
}
|
|
void Serialize( idVec6& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteVectorFloat( value );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadVectorFloat( value );
|
|
}
|
|
}
|
|
void Serialize( idVec4& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
msg->WriteVectorFloat( value );
|
|
}
|
|
else
|
|
{
|
|
msg->ReadVectorFloat( value );
|
|
}
|
|
}
|
|
|
|
// serialize an angle, normalized to between 0 to 360 and quantized to 16 bits
|
|
void SerializeAngle( float& value )
|
|
{
|
|
SanityCheck();
|
|
if( writing )
|
|
{
|
|
float nAngle = idMath::AngleNormalize360( value );
|
|
assert( nAngle >= 0.0f ); // should never get a negative angle
|
|
uint16 sAngle = nAngle * ( 65536.0f / 360.0f );
|
|
msg->WriteUShort( sAngle );
|
|
}
|
|
else
|
|
{
|
|
uint16 sAngle = msg->ReadUShort();
|
|
value = sAngle * ( 360.0f / 65536.0f );
|
|
}
|
|
|
|
}
|
|
|
|
//void Serialize( degrees_t & value ) {
|
|
// SanityCheck();
|
|
// float angle = value.Get();
|
|
// Serialize( angle );
|
|
// value.Set( angle );
|
|
// }
|
|
//void SerializeAngle( degrees_t & value ) {
|
|
// SanityCheck();
|
|
// float angle = value.Get();
|
|
// SerializeAngle( angle );
|
|
// value.Set( angle );
|
|
// }
|
|
//void Serialize( radians_t & value ) {
|
|
// SanityCheck();
|
|
// // convert to degrees
|
|
// degrees_t d( value.Get() * idMath::M_RAD2DEG );
|
|
// Serialize( d );
|
|
// if ( !writing ) {
|
|
// // if reading, get the value we read in degrees and convert back to radians
|
|
// value.Set( d.Get() * idMath::M_DEG2RAD );
|
|
// }
|
|
// }
|
|
//void SerializeAngle( radians_t & value ) {
|
|
// SanityCheck();
|
|
// // convert to degrees
|
|
// degrees_t d( value.Get() * idMath::M_RAD2DEG );
|
|
// // serialize as normalized degrees between 0 - 360
|
|
// SerializeAngle( d );
|
|
// if ( !writing ) {
|
|
// // if reading, get the value we read in degrees and convert back to radians
|
|
// value.Set( d.Get() * idMath::M_DEG2RAD );
|
|
// }
|
|
// }
|
|
//
|
|
//void Serialize( idColor & value ) {
|
|
// Serialize( value.r );
|
|
// Serialize( value.g );
|
|
// Serialize( value.b );
|
|
// Serialize( value.a );
|
|
//}
|
|
|
|
void SanityCheck()
|
|
{
|
|
#ifdef SERIALIZE_SANITYCHECK
|
|
if( writing )
|
|
{
|
|
msg->WriteUShort( 0xCCCC );
|
|
msg->WriteUShort( magic );
|
|
}
|
|
else
|
|
{
|
|
int cccc = msg->ReadUShort();
|
|
int m = msg->ReadUShort();
|
|
assert( cccc == 0xCCCC );
|
|
assert( m == magic );
|
|
// For release builds
|
|
if( cccc != 0xCCCC )
|
|
{
|
|
idLib::Error( "idSerializer::SanityCheck - cccc != 0xCCCC" );
|
|
}
|
|
if( m != magic )
|
|
{
|
|
idLib::Error( "idSerializer::SanityCheck - m != magic" );
|
|
}
|
|
}
|
|
magic++;
|
|
#endif
|
|
}
|
|
|
|
void SerializeCheckpoint( const char* file, int line )
|
|
{
|
|
#ifdef ENABLE_SERIALIZE_CHECKPOINTS
|
|
const uint32 tagValue = 0xABADF00D;
|
|
uint32 tag = tagValue;
|
|
Serialize( tag );
|
|
if( tag != tagValue )
|
|
{
|
|
idLib::Error( "SERIALIZE_CHECKPOINT: tag != tagValue (file: %s - line: %i)", file, line );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
idBitMsg& GetMsg()
|
|
{
|
|
return *msg;
|
|
}
|
|
|
|
private:
|
|
bool writing;
|
|
idBitMsg* msg;
|
|
#ifdef SERIALIZE_SANITYCHECK
|
|
int magic;
|
|
#endif
|
|
};
|
|
|
|
class idSerializerScopedBlock
|
|
{
|
|
public:
|
|
idSerializerScopedBlock( idSerializer& ser_, int maxSizeBytes_ )
|
|
{
|
|
ser = &ser_;
|
|
maxSizeBytes = maxSizeBytes_;
|
|
|
|
startByte = ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize();
|
|
startWriteBits = ser->GetMsg().GetWriteBit();
|
|
}
|
|
|
|
~idSerializerScopedBlock()
|
|
{
|
|
|
|
// Serialize remaining bits
|
|
while( ser->GetMsg().GetWriteBit() != startWriteBits )
|
|
{
|
|
ser->SerializeBoolNonRef( false );
|
|
}
|
|
|
|
// Verify we didn't go over
|
|
int endByte = ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize();
|
|
int sizeBytes = endByte - startByte;
|
|
if( !verify( sizeBytes <= maxSizeBytes ) )
|
|
{
|
|
idLib::Warning( "idSerializerScopedBlock went over maxSize (%d > %d)", sizeBytes, maxSizeBytes );
|
|
return;
|
|
}
|
|
|
|
// Serialize remaining bytes
|
|
uint8 b = 0;
|
|
while( sizeBytes < maxSizeBytes )
|
|
{
|
|
ser->Serialize( b );
|
|
sizeBytes++;
|
|
}
|
|
|
|
int finalSize = ( ( ser->IsReading() ? ser->GetMsg().GetReadCount() : ser->GetMsg().GetSize() ) - startByte );
|
|
verify( maxSizeBytes == finalSize );
|
|
}
|
|
|
|
private:
|
|
idSerializer* ser;
|
|
int maxSizeBytes;
|
|
|
|
int startByte;
|
|
int startWriteBits;
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
========================
|
|
idSerializer::SerializeQ
|
|
========================
|
|
*/
|
|
#ifndef SERIALIZE_NO_QUANT
|
|
ID_INLINE void idSerializer::SerializeQ( idMat3& axis, int bits )
|
|
{
|
|
SanityCheck();
|
|
|
|
const float scale = ( ( 1 << ( bits - 1 ) ) - 1 );
|
|
if( IsWriting() )
|
|
{
|
|
idQuat quat = axis.ToQuat();
|
|
|
|
int maxIndex = 0;
|
|
for( unsigned int i = 1; i < 4; i++ )
|
|
{
|
|
if( idMath::Fabs( quat[i] ) > idMath::Fabs( quat[maxIndex] ) )
|
|
{
|
|
maxIndex = i;
|
|
}
|
|
}
|
|
|
|
msg->WriteBits( maxIndex, 2 );
|
|
|
|
idVec3 out;
|
|
|
|
if( quat[maxIndex] < 0.0f )
|
|
{
|
|
out.x = -quat[( maxIndex + 1 ) & 3];
|
|
out.y = -quat[( maxIndex + 2 ) & 3];
|
|
out.z = -quat[( maxIndex + 3 ) & 3];
|
|
}
|
|
else
|
|
{
|
|
out.x = quat[( maxIndex + 1 ) & 3];
|
|
out.y = quat[( maxIndex + 2 ) & 3];
|
|
out.z = quat[( maxIndex + 3 ) & 3];
|
|
}
|
|
msg->WriteBits( idMath::Ftoi( out.x * scale ), -bits );
|
|
msg->WriteBits( idMath::Ftoi( out.y * scale ), -bits );
|
|
msg->WriteBits( idMath::Ftoi( out.z * scale ), -bits );
|
|
|
|
}
|
|
else if( IsReading() )
|
|
{
|
|
idQuat quat;
|
|
idVec3 in;
|
|
|
|
int maxIndex = msg->ReadBits( 2 );
|
|
|
|
in.x = ( float )msg->ReadBits( -bits ) / scale;
|
|
in.y = ( float )msg->ReadBits( -bits ) / scale;
|
|
in.z = ( float )msg->ReadBits( -bits ) / scale;
|
|
|
|
quat[( maxIndex + 1 ) & 3] = in.x;
|
|
quat[( maxIndex + 2 ) & 3] = in.y;
|
|
quat[( maxIndex + 3 ) & 3] = in.z;
|
|
|
|
quat[maxIndex] = idMath::Sqrt( idMath::Fabs( 1.0f - in.x * in.x - in.y * in.y - in.z * in.z ) );
|
|
|
|
axis = quat.ToMat3();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
========================
|
|
idSerializer::Serialize
|
|
========================
|
|
*/
|
|
ID_INLINE void idSerializer::Serialize( idMat3& axis )
|
|
{
|
|
SanityCheck();
|
|
|
|
Serialize( axis[0] );
|
|
Serialize( axis[1] );
|
|
Serialize( axis[2] );
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idSerializer::SerializeC
|
|
========================
|
|
*/
|
|
ID_INLINE void idSerializer::SerializeC( idMat3& axis )
|
|
{
|
|
SanityCheck();
|
|
|
|
if( IsWriting() )
|
|
{
|
|
idCQuat cquat = axis.ToCQuat();
|
|
|
|
Serialize( cquat.x );
|
|
Serialize( cquat.y );
|
|
Serialize( cquat.z );
|
|
}
|
|
else if( IsReading() )
|
|
{
|
|
idCQuat cquat;
|
|
|
|
Serialize( cquat.x );
|
|
Serialize( cquat.y );
|
|
Serialize( cquat.z );
|
|
|
|
axis = cquat.ToMat3();
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idSerializer::SerializeListElement
|
|
========================
|
|
*/
|
|
template< typename _type_ >
|
|
ID_INLINE void idSerializer::SerializeListElement( const idList<_type_* >& list, const _type_*& element )
|
|
{
|
|
SanityCheck();
|
|
|
|
if( IsWriting() )
|
|
{
|
|
int index = list.FindIndex( const_cast<_type_*>( element ) );
|
|
assert( index >= 0 );
|
|
SerializePacked( index );
|
|
}
|
|
else if( IsReading() )
|
|
{
|
|
int index = 0;
|
|
SerializePacked( index );
|
|
element = list[index];
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idSerializer::SerializePacked
|
|
Writes out 7 bits at a time, using every 8th bit to signify more bits exist
|
|
|
|
NOTE - Signed values work with this function, but take up more bytes
|
|
Use SerializeSPacked if you anticipate lots of negative values
|
|
========================
|
|
*/
|
|
ID_INLINE void idSerializer::SerializePacked( int& original )
|
|
{
|
|
SanityCheck();
|
|
|
|
if( IsWriting() )
|
|
{
|
|
uint32 value = original;
|
|
|
|
while( true )
|
|
{
|
|
uint8 byte = value & 0x7F;
|
|
value >>= 7;
|
|
byte |= value ? 0x80 : 0;
|
|
msg->WriteByte( byte ); // Emit byte
|
|
if( value == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint8 byte = 0x80;
|
|
uint32 value = 0;
|
|
int32 shift = 0;
|
|
|
|
while( byte & 0x80 && shift < 32 )
|
|
{
|
|
byte = msg->ReadByte();
|
|
value |= ( byte & 0x7F ) << shift;
|
|
shift += 7;
|
|
}
|
|
|
|
original = value;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idSerializer::SerializeSPacked
|
|
Writes out 7 bits at a time, using every 8th bit to signify more bits exist
|
|
|
|
NOTE - An extra bit of the first byte is used to store the sign
|
|
(this function supports negative values, but will use 2 bytes for values greater than 63)
|
|
========================
|
|
*/
|
|
ID_INLINE void idSerializer::SerializeSPacked( int& value )
|
|
{
|
|
SanityCheck();
|
|
|
|
if( IsWriting() )
|
|
{
|
|
|
|
uint32 uvalue = idMath::Abs( value );
|
|
|
|
// Write the first byte specifically to handle the sign bit
|
|
uint8 byte = uvalue & 0x3f;
|
|
byte |= value < 0 ? 0x40 : 0;
|
|
uvalue >>= 6;
|
|
byte |= uvalue > 0 ? 0x80 : 0;
|
|
|
|
msg->WriteByte( byte );
|
|
|
|
while( uvalue > 0 )
|
|
{
|
|
uint8 byte2 = uvalue & 0x7F;
|
|
uvalue >>= 7;
|
|
byte2 |= uvalue ? 0x80 : 0;
|
|
msg->WriteByte( byte2 ); // Emit byte
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Load the first byte specifically to handle the sign bit
|
|
uint8 byte = msg->ReadByte();
|
|
uint32 uvalue = byte & 0x3f;
|
|
bool sgn = ( byte & 0x40 ) ? true : false;
|
|
int32 shift = 6;
|
|
|
|
while( byte & 0x80 && shift < 32 )
|
|
{
|
|
byte = msg->ReadByte(); // Read byte
|
|
uvalue |= ( byte & 0x7F ) << shift;
|
|
shift += 7;
|
|
}
|
|
|
|
value = sgn ? -( ( int )uvalue ) : uvalue;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|