/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech 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. IceTech 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 IceTech Source Code. If not, see . In addition, the IceTech 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 IceTech 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 Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #ifndef __BITMSG_H__ #define __BITMSG_H__ /* =============================================================================== idBitMsg Handles byte ordering and avoids alignment errors. Allows concurrent writing and reading. The data set with Init is never freed. =============================================================================== */ class idBitMsg { public: idBitMsg(); ~idBitMsg() {} void Init(byte* data, int length); void Init(const byte* data, int length); byte* GetData(void); // get data for writing const byte* GetData(void) const; // get data for reading #ifdef QUAKE4 const byte* GetReadData(void) const; #endif int GetMaxSize(void) const; // get the maximum message size void SetAllowOverflow(bool set); // generate error if not set and message is overflowed bool IsOverflowed(void) const; // returns true if the message was overflowed int GetSize(void) const; // size of the message in bytes void SetSize(int size); // set the message size int GetWriteBit(void) const; // get current write bit void SetWriteBit(int bit); // set current write bit int GetNumBitsWritten(void) const; // returns number of bits written int GetRemainingWriteBits(void) const; // space left in bits for writing void SaveWriteState(int& s, int& b) const; // save the write state void RestoreWriteState(int s, int b); // restore the write state int GetReadCount(void) const; // bytes read so far void SetReadCount(int bytes); // set the number of bytes and bits read int GetReadBit(void) const; // get current read bit void SetReadBit(int bit); // set current read bit int GetNumBitsRead(void) const; // returns number of bits read int GetRemainingReadBits(void) const; // number of bits left to read void SaveReadState(int& c, int& b) const; // save the read state #ifdef QUAKE4 void RestoreReadState(int c, int b) const; // restore the read state #else void RestoreReadState(int c, int b); // restore the read state #endif void BeginWriting(void); // begin writing int GetRemainingSpace(void) const; // space left in bytes void WriteByteAlign(void); // write up to the next byte boundary void WriteBits(int value, int numBits); // write the specified number of bits void WriteChar(int c); void WriteByte(int c); void WriteShort(int c); void WriteUShort(int c); void WriteLong(int c); void WriteFloat(float f); void WriteFloat(float f, int exponentBits, int mantissaBits); void WriteAngle8(float f); void WriteAngle16(float f); void WriteDir(const idVec3& dir, int numBits); void WriteString(const char* s, int maxLength = -1, bool make7Bit = true); void WriteData(const void* data, int length); void WriteNetadr(const netadr_t adr); void WriteDeltaChar(int oldValue, int newValue); void WriteDeltaByte(int oldValue, int newValue); void WriteDeltaShort(int oldValue, int newValue); void WriteDeltaLong(int oldValue, int newValue); void WriteDeltaFloat(float oldValue, float newValue); void WriteDeltaFloat(float oldValue, float newValue, int exponentBits, int mantissaBits); void WriteDeltaByteCounter(int oldValue, int newValue); void WriteDeltaShortCounter(int oldValue, int newValue); void WriteDeltaLongCounter(int oldValue, int newValue); bool WriteDeltaDict(const idDict& dict, const idDict* base); void BeginReading(void) const; // begin reading. int GetRemaingData(void) const; // number of bytes left to read #ifdef QUAKE4 int GetRemainingData(void) const; // number of bytes left to read #endif void ReadByteAlign(void) const; // read up to the next byte boundary int ReadBits(int numBits) const; // read the specified number of bits int ReadChar(void) const; int ReadByte(void) const; int ReadShort(void) const; int ReadUShort(void) const; int ReadLong(void) const; float ReadFloat(void) const; float ReadFloat(int exponentBits, int mantissaBits) const; float ReadAngle8(void) const; float ReadAngle16(void) const; idVec3 ReadDir(int numBits) const; int ReadString(char* buffer, int bufferSize) const; int ReadData(void* data, int length) const; void ReadNetadr(netadr_t* adr) const; void WriteVec3(const idVec3& vector); void WriteMat3(const idMat3& axis); void WriteBool(bool boolean); idVec3 ReadVec3() const; idMat3 ReadMat3() const; bool ReadBool() const; int ReadDeltaChar(int oldValue) const; int ReadDeltaByte(int oldValue) const; int ReadDeltaShort(int oldValue) const; int ReadDeltaLong(int oldValue) const; float ReadDeltaFloat(float oldValue) const; float ReadDeltaFloat(float oldValue, int exponentBits, int mantissaBits) const; int ReadDeltaByteCounter(int oldValue) const; int ReadDeltaShortCounter(int oldValue) const; int ReadDeltaLongCounter(int oldValue) const; bool ReadDeltaDict(idDict& dict, const idDict* base) const; static int DirToBits(const idVec3& dir, int numBits); static idVec3 BitsToDir(int bits, int numBits); private: byte* writeData; // pointer to data for writing const byte* readData; // pointer to data for reading int maxSize; // maximum size of message in bytes int curSize; // current size of message in bytes int writeBit; // number of bits written to the last written byte mutable int readCount; // number of bytes read so far mutable int readBit; // number of bits read from the last read byte bool allowOverflow; // if false, generate an error when the message is overflowed bool overflowed; // set to true if the buffer size failed (with allowOverflow set) private: bool CheckOverflow(int numBits); byte* GetByteSpace(int length); void WriteDelta(int oldValue, int newValue, int numBits); int ReadDelta(int oldValue, int numBits) const; }; ID_INLINE void idBitMsg::Init(byte* data, int length) { writeData = data; readData = data; maxSize = length; } ID_INLINE void idBitMsg::Init(const byte* data, int length) { writeData = NULL; readData = data; maxSize = length; } ID_INLINE byte* idBitMsg::GetData(void) { return writeData; } ID_INLINE const byte* idBitMsg::GetData(void) const { return readData; } #ifdef QUAKE4 ID_INLINE const byte* idBitMsg::GetReadData(void) const { return (readData + readCount); } #endif ID_INLINE int idBitMsg::GetMaxSize(void) const { return maxSize; } ID_INLINE void idBitMsg::SetAllowOverflow(bool set) { allowOverflow = set; } ID_INLINE bool idBitMsg::IsOverflowed(void) const { return overflowed; } ID_INLINE int idBitMsg::GetSize(void) const { return curSize; } ID_INLINE void idBitMsg::SetSize(int size) { if (size > maxSize) { curSize = maxSize; } else { curSize = size; } } ID_INLINE int idBitMsg::GetWriteBit(void) const { return writeBit; } ID_INLINE void idBitMsg::SetWriteBit(int bit) { writeBit = bit & 7; if (writeBit) { writeData[curSize - 1] &= (1 << writeBit) - 1; } } ID_INLINE int idBitMsg::GetNumBitsWritten(void) const { return ((curSize << 3) - ((8 - writeBit) & 7)); } ID_INLINE int idBitMsg::GetRemainingWriteBits(void) const { return (maxSize << 3) - GetNumBitsWritten(); } ID_INLINE void idBitMsg::SaveWriteState(int& s, int& b) const { s = curSize; b = writeBit; } ID_INLINE void idBitMsg::RestoreWriteState(int s, int b) { curSize = s; writeBit = b & 7; if (writeBit) { writeData[curSize - 1] &= (1 << writeBit) - 1; } } ID_INLINE int idBitMsg::GetReadCount(void) const { return readCount; } ID_INLINE void idBitMsg::SetReadCount(int bytes) { readCount = bytes; } ID_INLINE int idBitMsg::GetReadBit(void) const { return readBit; } ID_INLINE void idBitMsg::SetReadBit(int bit) { readBit = bit & 7; } ID_INLINE int idBitMsg::GetNumBitsRead(void) const { return ((readCount << 3) - ((8 - readBit) & 7)); } ID_INLINE int idBitMsg::GetRemainingReadBits(void) const { return (curSize << 3) - GetNumBitsRead(); } ID_INLINE void idBitMsg::SaveReadState(int& c, int& b) const { c = readCount; b = readBit; } #ifdef QUAKE4 ID_INLINE void idBitMsg::RestoreReadState(int c, int b) const { readCount = c; readBit = b & 7; } #else ID_INLINE void idBitMsg::RestoreReadState(int c, int b) { readCount = c; readBit = b & 7; } #endif ID_INLINE void idBitMsg::BeginWriting(void) { curSize = 0; overflowed = false; writeBit = 0; } ID_INLINE int idBitMsg::GetRemainingSpace(void) const { return maxSize - curSize; } ID_INLINE void idBitMsg::WriteByteAlign(void) { writeBit = 0; } ID_INLINE void idBitMsg::WriteChar(int c) { WriteBits(c, -8); } ID_INLINE void idBitMsg::WriteByte(int c) { WriteBits(c, 8); } ID_INLINE void idBitMsg::WriteShort(int c) { WriteBits(c, -16); } ID_INLINE void idBitMsg::WriteUShort(int c) { WriteBits(c, 16); } ID_INLINE void idBitMsg::WriteLong(int c) { WriteBits(c, 32); } ID_INLINE void idBitMsg::WriteFloat(float f) { WriteBits(*reinterpret_cast(&f), 32); } ID_INLINE void idBitMsg::WriteFloat(float f, int exponentBits, int mantissaBits) { int bits = idMath::FloatToBits(f, exponentBits, mantissaBits); WriteBits(bits, 1 + exponentBits + mantissaBits); } ID_INLINE void idBitMsg::WriteAngle8(float f) { WriteByte(ANGLE2BYTE(f)); } ID_INLINE void idBitMsg::WriteAngle16(float f) { WriteShort(ANGLE2SHORT(f)); } ID_INLINE void idBitMsg::WriteDir(const idVec3& dir, int numBits) { WriteBits(DirToBits(dir, numBits), numBits); } ID_INLINE void idBitMsg::WriteDeltaChar(int oldValue, int newValue) { WriteDelta(oldValue, newValue, -8); } ID_INLINE void idBitMsg::WriteDeltaByte(int oldValue, int newValue) { WriteDelta(oldValue, newValue, 8); } ID_INLINE void idBitMsg::WriteDeltaShort(int oldValue, int newValue) { WriteDelta(oldValue, newValue, -16); } ID_INLINE void idBitMsg::WriteDeltaLong(int oldValue, int newValue) { WriteDelta(oldValue, newValue, 32); } ID_INLINE void idBitMsg::WriteDeltaFloat(float oldValue, float newValue) { WriteDelta(*reinterpret_cast(&oldValue), *reinterpret_cast(&newValue), 32); } ID_INLINE void idBitMsg::WriteDeltaFloat(float oldValue, float newValue, int exponentBits, int mantissaBits) { int oldBits = idMath::FloatToBits(oldValue, exponentBits, mantissaBits); int newBits = idMath::FloatToBits(newValue, exponentBits, mantissaBits); WriteDelta(oldBits, newBits, 1 + exponentBits + mantissaBits); } ID_INLINE void idBitMsg::BeginReading(void) const { readCount = 0; readBit = 0; } ID_INLINE int idBitMsg::GetRemaingData(void) const { return curSize - readCount; } #ifdef QUAKE4 ID_INLINE int idBitMsg::GetRemainingData(void) const { return curSize - readCount; } #endif ID_INLINE void idBitMsg::ReadByteAlign(void) const { readBit = 0; } ID_INLINE int idBitMsg::ReadChar(void) const { return (signed char)ReadBits(-8); } ID_INLINE int idBitMsg::ReadByte(void) const { return (unsigned char)ReadBits(8); } ID_INLINE int idBitMsg::ReadShort(void) const { return (short)ReadBits(-16); } ID_INLINE int idBitMsg::ReadUShort(void) const { return (unsigned short)ReadBits(16); } ID_INLINE int idBitMsg::ReadLong(void) const { return ReadBits(32); } ID_INLINE float idBitMsg::ReadFloat(void) const { float value; *reinterpret_cast(&value) = ReadBits(32); return value; } ID_INLINE float idBitMsg::ReadFloat(int exponentBits, int mantissaBits) const { int bits = ReadBits(1 + exponentBits + mantissaBits); return idMath::BitsToFloat(bits, exponentBits, mantissaBits); } ID_INLINE float idBitMsg::ReadAngle8(void) const { return BYTE2ANGLE(ReadByte()); } ID_INLINE float idBitMsg::ReadAngle16(void) const { return SHORT2ANGLE(ReadShort()); } ID_INLINE idVec3 idBitMsg::ReadDir(int numBits) const { return BitsToDir(ReadBits(numBits), numBits); } ID_INLINE int idBitMsg::ReadDeltaChar(int oldValue) const { return (signed char)ReadDelta(oldValue, -8); } ID_INLINE int idBitMsg::ReadDeltaByte(int oldValue) const { return (unsigned char)ReadDelta(oldValue, 8); } ID_INLINE int idBitMsg::ReadDeltaShort(int oldValue) const { return (short)ReadDelta(oldValue, -16); } ID_INLINE int idBitMsg::ReadDeltaLong(int oldValue) const { return ReadDelta(oldValue, 32); } ID_INLINE float idBitMsg::ReadDeltaFloat(float oldValue) const { float value; *reinterpret_cast(&value) = ReadDelta(*reinterpret_cast(&oldValue), 32); return value; } ID_INLINE float idBitMsg::ReadDeltaFloat(float oldValue, int exponentBits, int mantissaBits) const { int oldBits = idMath::FloatToBits(oldValue, exponentBits, mantissaBits); int newBits = ReadDelta(oldBits, 1 + exponentBits + mantissaBits); return idMath::BitsToFloat(newBits, exponentBits, mantissaBits); } ID_INLINE void idBitMsg::WriteVec3(const idVec3& vector) { WriteFloat(vector[0]); WriteFloat(vector[1]); WriteFloat(vector[2]); } ID_INLINE void idBitMsg::WriteMat3(const idMat3& axis) { WriteVec3(axis[0]); WriteVec3(axis[1]); WriteVec3(axis[2]); } ID_INLINE void idBitMsg::WriteBool(bool boolean) { WriteBits(boolean, 1); } ID_INLINE idVec3 idBitMsg::ReadVec3() const { idVec3 vector; vector[0] = ReadFloat(); vector[1] = ReadFloat(); vector[2] = ReadFloat(); return vector; } ID_INLINE idMat3 idBitMsg::ReadMat3() const { idMat3 axis; axis[0] = ReadVec3(); axis[1] = ReadVec3(); axis[2] = ReadVec3(); return axis; } ID_INLINE bool idBitMsg::ReadBool() const { int boolean = ReadBits(1); return *(bool*)&boolean;//We seem to get a performance warning unless I do this. Ick! } /* =============================================================================== idBitMsgDelta =============================================================================== */ class idBitMsgDelta { public: idBitMsgDelta(); ~idBitMsgDelta() {} void Init(const idBitMsg* base, idBitMsg* newBase, idBitMsg* delta); void Init(const idBitMsg* base, idBitMsg* newBase, const idBitMsg* delta); #ifdef QUAKE4 void InitWriting(const idBitMsg* base, idBitMsg* newBase, idBitMsg* delta); void InitReading(const idBitMsg* base, idBitMsg* newBase, const idBitMsg* delta); #endif bool HasChanged(void) const; void WriteBits(int value, int numBits); void WriteChar(int c); void WriteByte(int c); void WriteShort(int c); void WriteUShort(int c); void WriteLong(int c); void WriteFloat(float f); void WriteFloat(float f, int exponentBits, int mantissaBits); #ifdef QUAKE4 void WriteVec3(const idVec3& v); void WriteDeltaVec3(const idVec3& oldValue, const idVec3& newValue); void WriteVec4(const idVec4& v); void WriteDeltaVec4(const idVec4& oldValue, const idVec4& newValue); void WriteQuat(const idQuat& q); void WriteDeltaQuat(const idQuat& oldValue, const idQuat& newValue); void WriteMat3(const idMat3& m); void WriteDeltaMat3(const idMat3& oldValue, const idMat3& newValue); #endif void WriteAngle8(float f); void WriteAngle16(float f); void WriteDir(const idVec3& dir, int numBits); void WriteString(const char* s, int maxLength = -1); void WriteData(const void* data, int length); void WriteDict(const idDict& dict); void WriteDeltaChar(int oldValue, int newValue); void WriteDeltaByte(int oldValue, int newValue); void WriteDeltaShort(int oldValue, int newValue); void WriteDeltaLong(int oldValue, int newValue); void WriteDeltaFloat(float oldValue, float newValue); void WriteDeltaFloat(float oldValue, float newValue, int exponentBits, int mantissaBits); void WriteDeltaByteCounter(int oldValue, int newValue); void WriteDeltaShortCounter(int oldValue, int newValue); void WriteDeltaLongCounter(int oldValue, int newValue); int ReadBits(int numBits) const; int ReadChar(void) const; int ReadByte(void) const; int ReadShort(void) const; int ReadUShort(void) const; int ReadLong(void) const; float ReadFloat(void) const; float ReadFloat(int exponentBits, int mantissaBits) const; #ifdef QUAKE4 idVec3 ReadVec3(void) const; idVec3 ReadDeltaVec3(const idVec3& oldValue) const; idVec4 ReadVec4(void) const; idVec4 ReadDeltaVec4(const idVec4& oldValue) const; idQuat ReadQuat(void) const; idQuat ReadDeltaQuat(const idQuat& oldValue) const; idMat3 ReadMat3(void) const; idMat3 ReadDeltaMat3(const idMat3& oldValue) const; #endif float ReadAngle8(void) const; float ReadAngle16(void) const; idVec3 ReadDir(int numBits) const; void ReadString(char* buffer, int bufferSize) const; void ReadData(void* data, int length) const; void ReadDict(idDict& dict); int ReadDeltaChar(int oldValue) const; int ReadDeltaByte(int oldValue) const; int ReadDeltaShort(int oldValue) const; int ReadDeltaLong(int oldValue) const; float ReadDeltaFloat(float oldValue) const; float ReadDeltaFloat(float oldValue, int exponentBits, int mantissaBits) const; int ReadDeltaByteCounter(int oldValue) const; int ReadDeltaShortCounter(int oldValue) const; int ReadDeltaLongCounter(int oldValue) const; private: const idBitMsg* base; // base idBitMsg* newBase; // new base idBitMsg* writeDelta; // delta from base to new base for writing const idBitMsg* readDelta; // delta from base to new base for reading mutable bool changed; // true if the new base is different from the base private: void WriteDelta(int oldValue, int newValue, int numBits); int ReadDelta(int oldValue, int numBits) const; }; ID_INLINE idBitMsgDelta::idBitMsgDelta() { base = NULL; newBase = NULL; writeDelta = NULL; readDelta = NULL; changed = false; } ID_INLINE void idBitMsgDelta::Init(const idBitMsg* base, idBitMsg* newBase, idBitMsg* delta) { this->base = base; this->newBase = newBase; this->writeDelta = delta; this->readDelta = delta; this->changed = false; } ID_INLINE void idBitMsgDelta::Init(const idBitMsg* base, idBitMsg* newBase, const idBitMsg* delta) { this->base = base; this->newBase = newBase; this->writeDelta = NULL; this->readDelta = delta; this->changed = false; } #ifdef QUAKE4 ID_INLINE void idBitMsgDelta::InitWriting(const idBitMsg* base, idBitMsg* newBase, idBitMsg* delta) { Init(base, newBase, delta); } ID_INLINE void idBitMsgDelta::InitReading(const idBitMsg* base, idBitMsg* newBase, const idBitMsg* delta) { Init(base, newBase, delta); } #endif ID_INLINE bool idBitMsgDelta::HasChanged(void) const { return changed; } ID_INLINE void idBitMsgDelta::WriteChar(int c) { WriteBits(c, -8); } ID_INLINE void idBitMsgDelta::WriteByte(int c) { WriteBits(c, 8); } ID_INLINE void idBitMsgDelta::WriteShort(int c) { WriteBits(c, -16); } ID_INLINE void idBitMsgDelta::WriteUShort(int c) { WriteBits(c, 16); } ID_INLINE void idBitMsgDelta::WriteLong(int c) { WriteBits(c, 32); } ID_INLINE void idBitMsgDelta::WriteFloat(float f) { WriteBits(*reinterpret_cast(&f), 32); } ID_INLINE void idBitMsgDelta::WriteFloat(float f, int exponentBits, int mantissaBits) { int bits = idMath::FloatToBits(f, exponentBits, mantissaBits); WriteBits(bits, 1 + exponentBits + mantissaBits); } #ifdef QUAKE4 ID_INLINE void idBitMsgDelta::WriteVec3(const idVec3& v) { for (int ix = 0; ix < v.GetDimension(); ++ix) { WriteFloat(v[ix]); } } ID_INLINE void idBitMsgDelta::WriteDeltaVec3(const idVec3& oldValue, const idVec3& newValue) { for (int ix = 0; ix < oldValue.GetDimension(); ++ix) { WriteDeltaFloat(oldValue[ix], newValue[ix]); } } ID_INLINE void idBitMsgDelta::WriteVec4(const idVec4& v) { for (int ix = 0; ix < v.GetDimension(); ++ix) { WriteFloat(v[ix]); } } ID_INLINE void idBitMsgDelta::WriteDeltaVec4(const idVec4& oldValue, const idVec4& newValue) { for (int ix = 0; ix < oldValue.GetDimension(); ++ix) { WriteDeltaFloat(oldValue[ix], newValue[ix]); } } ID_INLINE void idBitMsgDelta::WriteQuat(const idQuat& q) { for (int ix = 0; ix < q.GetDimension(); ++ix) { WriteFloat(q[ix]); } } ID_INLINE void idBitMsgDelta::WriteDeltaQuat(const idQuat& oldValue, const idQuat& newValue) { for (int ix = 0; ix < oldValue.GetDimension(); ++ix) { WriteDeltaFloat(oldValue[ix], newValue[ix]); } } ID_INLINE void idBitMsgDelta::WriteMat3(const idMat3& m) { for (int ix = 0; ix < m.GetVec3Dimension(); ++ix) { WriteVec3(m[ix]); } } ID_INLINE void idBitMsgDelta::WriteDeltaMat3(const idMat3& oldValue, const idMat3& newValue) { for (int ix = 0; ix < oldValue.GetVec3Dimension(); ++ix) { WriteDeltaVec3(oldValue[ix], newValue[ix]); } } #endif ID_INLINE void idBitMsgDelta::WriteAngle8(float f) { WriteBits(ANGLE2BYTE(f), 8); } ID_INLINE void idBitMsgDelta::WriteAngle16(float f) { WriteBits(ANGLE2SHORT(f), 16); } ID_INLINE void idBitMsgDelta::WriteDir(const idVec3& dir, int numBits) { WriteBits(idBitMsg::DirToBits(dir, numBits), numBits); } ID_INLINE void idBitMsgDelta::WriteDeltaChar(int oldValue, int newValue) { WriteDelta(oldValue, newValue, -8); } ID_INLINE void idBitMsgDelta::WriteDeltaByte(int oldValue, int newValue) { WriteDelta(oldValue, newValue, 8); } ID_INLINE void idBitMsgDelta::WriteDeltaShort(int oldValue, int newValue) { WriteDelta(oldValue, newValue, -16); } ID_INLINE void idBitMsgDelta::WriteDeltaLong(int oldValue, int newValue) { WriteDelta(oldValue, newValue, 32); } ID_INLINE void idBitMsgDelta::WriteDeltaFloat(float oldValue, float newValue) { WriteDelta(*reinterpret_cast(&oldValue), *reinterpret_cast(&newValue), 32); } ID_INLINE void idBitMsgDelta::WriteDeltaFloat(float oldValue, float newValue, int exponentBits, int mantissaBits) { int oldBits = idMath::FloatToBits(oldValue, exponentBits, mantissaBits); int newBits = idMath::FloatToBits(newValue, exponentBits, mantissaBits); WriteDelta(oldBits, newBits, 1 + exponentBits + mantissaBits); } ID_INLINE int idBitMsgDelta::ReadChar(void) const { return (signed char)ReadBits(-8); } ID_INLINE int idBitMsgDelta::ReadByte(void) const { return (unsigned char)ReadBits(8); } ID_INLINE int idBitMsgDelta::ReadShort(void) const { return (short)ReadBits(-16); } ID_INLINE int idBitMsgDelta::ReadUShort(void) const { return (unsigned short)ReadBits(16); } ID_INLINE int idBitMsgDelta::ReadLong(void) const { return ReadBits(32); } ID_INLINE float idBitMsgDelta::ReadFloat(void) const { float value; *reinterpret_cast(&value) = ReadBits(32); return value; } ID_INLINE float idBitMsgDelta::ReadFloat(int exponentBits, int mantissaBits) const { int bits = ReadBits(1 + exponentBits + mantissaBits); return idMath::BitsToFloat(bits, exponentBits, mantissaBits); } #ifdef QUAKE4 ID_INLINE idVec3 idBitMsgDelta::ReadVec3(void) const { idVec3 v; for (int ix = 0; ix < v.GetDimension(); ++ix) { v[ix] = ReadFloat(); } return v; } ID_INLINE idVec3 idBitMsgDelta::ReadDeltaVec3(const idVec3& oldValue) const { idVec3 value; for (int ix = 0; ix < value.GetDimension(); ++ix) { value[ix] = ReadDeltaFloat(oldValue[ix]); } return value; } ID_INLINE idVec4 idBitMsgDelta::ReadVec4(void) const { idVec4 v; for (int ix = 0; ix < v.GetDimension(); ++ix) { v[ix] = ReadFloat(); } return v; } ID_INLINE idVec4 idBitMsgDelta::ReadDeltaVec4(const idVec4& oldValue) const { idVec4 value; for (int ix = 0; ix < value.GetDimension(); ++ix) { value[ix] = ReadDeltaFloat(oldValue[ix]); } return value; } ID_INLINE idQuat idBitMsgDelta::ReadQuat(void) const { idQuat q; for (int ix = 0; ix < q.GetDimension(); ++ix) { q[ix] = ReadFloat(); } return q; } ID_INLINE idQuat idBitMsgDelta::ReadDeltaQuat(const idQuat& oldValue) const { idQuat value; for (int ix = 0; ix < value.GetDimension(); ++ix) { value[ix] = ReadDeltaFloat(oldValue[ix]); } return value; } ID_INLINE idMat3 idBitMsgDelta::ReadMat3(void) const { idMat3 m; for (int ix = 0; ix < m.GetVec3Dimension(); ++ix) { m[ix] = ReadVec3(); } return m; } ID_INLINE idMat3 idBitMsgDelta::ReadDeltaMat3(const idMat3& oldValue) const { idMat3 value; for (int ix = 0; ix < value.GetVec3Dimension(); ++ix) { value[ix] = ReadDeltaVec3(oldValue[ix]); } return value; } #endif ID_INLINE float idBitMsgDelta::ReadAngle8(void) const { return BYTE2ANGLE(ReadByte()); } ID_INLINE float idBitMsgDelta::ReadAngle16(void) const { return SHORT2ANGLE(ReadShort()); } ID_INLINE idVec3 idBitMsgDelta::ReadDir(int numBits) const { return idBitMsg::BitsToDir(ReadBits(numBits), numBits); } ID_INLINE int idBitMsgDelta::ReadDeltaChar(int oldValue) const { return (signed char)ReadDelta(oldValue, -8); } ID_INLINE int idBitMsgDelta::ReadDeltaByte(int oldValue) const { return (unsigned char)ReadDelta(oldValue, 8); } ID_INLINE int idBitMsgDelta::ReadDeltaShort(int oldValue) const { return (short)ReadDelta(oldValue, -16); } ID_INLINE int idBitMsgDelta::ReadDeltaLong(int oldValue) const { return ReadDelta(oldValue, 32); } ID_INLINE float idBitMsgDelta::ReadDeltaFloat(float oldValue) const { float value; *reinterpret_cast(&value) = ReadDelta(*reinterpret_cast(&oldValue), 32); return value; } ID_INLINE float idBitMsgDelta::ReadDeltaFloat(float oldValue, int exponentBits, int mantissaBits) const { int oldBits = idMath::FloatToBits(oldValue, exponentBits, mantissaBits); int newBits = ReadDelta(oldBits, 1 + exponentBits + mantissaBits); return idMath::BitsToFloat(newBits, exponentBits, mantissaBits); } #ifdef QUAKE4 #define MAX_MSG_QUEUE_SIZE 16384 // must be a power of 2 class idMsgQueue { public: idMsgQueue(); void Init(int sequence); bool Add(const byte* data, const int size, bool sequencing); // prepend to a message without the need to a memcopy and readjust bool AddConcat(const byte* data1, const int size1, const byte* data2, const int size2, bool sequencing); bool Get(byte* data, int dataSize, int& size, bool sequencing); int GetTotalSize(void) const; int GetSpaceLeft(void) const; int GetFirst(void) const { return first; } int GetLast(void) const { return last; } void CopyToBuffer(byte* buf) const; void WriteTo(idBitMsg& msg); void FlushTo(idBitMsg& msg); void ReadFrom(const idBitMsg& msg); void Save(idFile* file) const; void Restore(idFile* file); private: byte buffer[MAX_MSG_QUEUE_SIZE]; int first; // sequence number of first message in queue int last; // sequence number of last message in queue int startIndex; // index pointing to the first byte of the first message int endIndex; // index pointing to the first byte after the last message public: void WriteByte(byte b); byte ReadByte(void); void WriteShort(int s); void WriteUShort(int s); int ReadShort(void); int ReadUShort(void); void WriteLong(int l); int ReadLong(void); void WriteData(const byte* data, const int size); void ReadData(byte* data, const int size); }; class idBitMsgQueue { public: idBitMsgQueue(); void Init(void); void Add(const idBitMsg& msg, const int timestamp); bool Get(idBitMsg& msg, int& timestamp); bool Get(idBitMsg& msg) { int dummy; return Get(msg, dummy); } bool GetTimestamp(int& timestamp); private: int nextTimestamp; bool readTimestamp; idLinkList writeList, readList; }; #endif #endif /* !__BITMSG_H__ */