Files
DoomRTX/neo/engine/idlib/BitMsg.h
T
2026-05-09 22:10:40 -07:00

965 lines
28 KiB
C++

/*
===========================================================================
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 <http://www.gnu.org/licenses/>.
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<int*>(&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<int*>(&oldValue), *reinterpret_cast<int*>(&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<int*>(&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<int*>(&value) = ReadDelta(*reinterpret_cast<int*>(&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<int*>(&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<int*>(&oldValue), *reinterpret_cast<int*>(&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<int*>(&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<int*>(&value) = ReadDelta(*reinterpret_cast<int*>(&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<idMsgQueue> writeList, readList;
};
#endif
#endif /* !__BITMSG_H__ */