bitStream.h
Engine/source/core/stream/bitStream.h
Classes:
class
class
This class acts to provide an "infinitely extending" stream.
class
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#ifndef _BITSTREAM_H_ 30#define _BITSTREAM_H_ 31 32#ifndef _STREAM_H_ 33#include "core/stream/stream.h" 34#endif 35#ifndef _MPOINT3_H_ 36#include "math/mPoint3.h" 37#endif 38#ifndef _CRC_H_ 39#include "core/crc.h" 40#endif 41 42//-------------------------------------- Some caveats when using this class: 43// - Get/setPosition semantics are changed 44// to indicate bit position rather than 45// byte position. 46// 47 48class Point3F; 49class MatrixF; 50class HuffmanProcessor; 51class BitVector; 52class QuatF; 53 54class BitStream : public Stream 55{ 56protected: 57 U8 *mDataPtr; 58 S32 bitNum; 59 S32 bufSize; 60 bool error; 61 S32 maxReadBitNum; 62 S32 maxWriteBitNum; 63 char *stringBuffer; 64 Point3F mCompressPoint; 65 66 friend class HuffmanProcessor; 67public: 68 static BitStream *getPacketStream(U32 writeSize = 0); 69 static void sendPacketStream(const NetAddress *addr); 70 71 void setBuffer(void *bufPtr, S32 bufSize, S32 maxSize = 0); 72 U8* getBuffer() { return mDataPtr; } 73 U8* getBytePtr(); 74 75 U32 getReadByteSize(); 76 U32 getWriteByteSize(); 77 78 S32 getCurPos() const; 79 void setCurPos(const U32); 80 81 // HACK: We reverted BitStream to this previous version 82 // because it was crashing the build. 83 // 84 // These are just here so that we don't have to revert 85 // the changes from the rest of the code. 86 // 87 // 9/11/2008 - Tom Spilman 88 // 89 S32 getBitPosition() const { return getCurPos(); } 90 void clearStringBuffer(); 91 92 BitStream(void *bufPtr, S32 bufSize, S32 maxWriteSize = -1) { setBuffer(bufPtr, bufSize,maxWriteSize); stringBuffer = NULL; } 93 void clear(); 94 95 void setStringBuffer(char buffer[256]); 96 void writeInt(S32 value, S32 bitCount); 97 S32 readInt(S32 bitCount); 98 99 /// Use this method to write out values in a concise but ass backwards way... 100 /// Good for values you expect to be frequently zero, often small. Worst case 101 /// this will bloat values by nearly 20% (5 extra bits!) Best case you'll get 102 /// one bit (if it's zero). 103 /// 104 /// This is not so much for efficiency's sake, as to make life painful for 105 /// people that want to reverse engineer our network or file formats. 106 void writeCussedU32(U32 val) 107 { 108 // Is it zero? 109 if(writeFlag(val == 0)) 110 return; 111 112 if(writeFlag(val <= 0xF)) // 4 bit 113 writeRangedU32(val, 0, 0xF); 114 else if(writeFlag(val <= 0xFF)) // 8 bit 115 writeRangedU32(val, 0, 0xFF); 116 else if(writeFlag(val <= 0xFFFF)) // 16 bit 117 writeRangedU32(val, 0, 0xFFFF); 118 else if(writeFlag(val <= 0xFFFFFF)) // 24 bit 119 writeRangedU32(val, 0, 0xFFFFFF); 120 else 121 writeRangedU32(val, 0, 0xFFFFFFFF); 122 } 123 124 U32 readCussedU32() 125 { 126 if(readFlag()) 127 return 0; 128 129 if(readFlag()) 130 return readRangedU32(0, 0xF); 131 else if(readFlag()) 132 return readRangedU32(0, 0xFF); 133 else if(readFlag()) 134 return readRangedU32(0, 0xFFFF); 135 else if(readFlag()) 136 return readRangedU32(0, 0xFFFFFF); 137 else 138 return readRangedU32(0, 0xFFFFFFFF); 139 } 140 141 void writeSignedInt(S32 value, S32 bitCount); 142 S32 readSignedInt(S32 bitCount); 143 144 void writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd); 145 U32 readRangedU32(U32 rangeStart, U32 rangeEnd); 146 147 /// Writes a clamped signed integer to the stream using 148 /// an optimal amount of bits for the range. 149 void writeRangedS32( S32 value, S32 min, S32 max ); 150 151 /// Reads a ranged signed integer written with writeRangedS32. 152 S32 readRangedS32( S32 min, S32 max ); 153 154 // read and write floats... floats are 0 to 1 inclusive, signed floats are -1 to 1 inclusive 155 156 F32 readFloat(S32 bitCount); 157 F32 readSignedFloat(S32 bitCount); 158 159 void writeFloat(F32 f, S32 bitCount); 160 void writeSignedFloat(F32 f, S32 bitCount); 161 162 /// Writes a clamped floating point value to the 163 /// stream with the desired bits of precision. 164 void writeRangedF32( F32 value, F32 min, F32 max, U32 numBits ); 165 166 /// Reads a ranged floating point value written with writeRangedF32. 167 F32 readRangedF32( F32 min, F32 max, U32 numBits ); 168 169 void writeClassId(U32 classId, U32 classType, U32 classGroup); 170 S32 readClassId(U32 classType, U32 classGroup); // returns -1 if the class type is out of range 171 172 // writes a normalized vector 173 void writeNormalVector(const Point3F& vec, S32 bitCount); 174 void readNormalVector(Point3F *vec, S32 bitCount); 175 176 void clearCompressionPoint(); 177 void setCompressionPoint(const Point3F& p); 178 179 // Matching calls to these compression methods must, of course, 180 // have matching scale values. 181 void writeCompressedPoint(const Point3F& p,F32 scale = 0.001f); 182 void readCompressedPoint(Point3F* p,F32 scale = 0.001f); 183 184 // Uses the above method to reduce the precision of a normal vector so the server can 185 // determine exactly what is on the client. (Pre-dumbing the vector before sending 186 // to the client can result in precision errors...) 187 static Point3F dumbDownNormal(const Point3F& vec, S32 bitCount); 188 189 /// Writes a compressed vector as separate magnitude and 190 /// normal components. The final space used depends on the 191 /// content of the vector. 192 /// 193 /// - 1 bit is used to skip over zero length vectors. 194 /// - 1 bit is used to mark if the magnitude exceeds max. 195 /// - The magnitude as: 196 /// a. magBits if less than maxMag. 197 /// b. a full 32bit value if greater than maxMag. 198 /// - The normal as a phi and theta sized normalBits+1 and normalBits. 199 /// 200 void writeVector( Point3F vec, F32 maxMag, S32 magBits, S32 normalBits ); 201 202 /// Reads a compressed vector. 203 /// @see writeVector 204 void readVector( Point3F *outVec, F32 maxMag, S32 magBits, S32 normalBits ); 205 206 // writes an affine transform (full precision version) 207 void writeAffineTransform(const MatrixF&); 208 void readAffineTransform(MatrixF*); 209 210 /// Writes a quaternion in a lossy compressed format that 211 /// is ( bitCount * 3 ) + 2 bits in size. 212 /// 213 /// @param quat The normalized quaternion to write. 214 /// @param bitCount The the storage space for the packed components of 215 /// the quaternion. 216 /// 217 void writeQuat( const QuatF& quat, U32 bitCount = 9 ); 218 219 /// Reads a quaternion written with writeQuat. 220 /// 221 /// @param quat The quaternion that was read. 222 /// @param bitCount The the storage space for the packed components of 223 /// the quaternion. Must match the bitCount at write. 224 /// @see writeQuat 225 /// 226 void readQuat( QuatF *outQuat, U32 bitCount = 9 ); 227 228 virtual void writeBits(S32 bitCount, const void *bitPtr); 229 virtual void readBits(S32 bitCount, void *bitPtr); 230 virtual bool writeFlag(bool val); 231 232 inline bool writeFlag(U32 val) 233 { 234 return writeFlag(val != 0); 235 } 236 237 inline bool writeFlag(void *val) 238 { 239 return writeFlag(val != 0); 240 } 241 242 virtual bool readFlag(); 243 244 void writeBits(const BitVector &bitvec); 245 void readBits(BitVector *bitvec); 246 247 void setBit(S32 bitCount, bool set); 248 bool testBit(S32 bitCount); 249 250 bool isFull() { return bitNum > (bufSize << 3); } 251 bool isValid() { return !error; } 252 253 bool _read (const U32 size,void* d); 254 bool _write(const U32 size,const void* d); 255 256 void readString(char stringBuf[256]); 257 void writeString(const char *stringBuf, S32 maxLen=255); 258 259 bool hasCapability(const Capability) const { return true; } 260 U32 getPosition() const; 261 bool setPosition(const U32 in_newPosition); 262 U32 getStreamSize(); 263 S32 getMaxWriteBitNum() const { return maxWriteBitNum; } 264}; 265 266class ResizeBitStream : public BitStream 267{ 268protected: 269 U32 mMinSpace; 270public: 271 ResizeBitStream(U32 minSpace = 1500, U32 initialSize = 0); 272 void validate(); 273 ~ResizeBitStream(); 274}; 275 276/// This class acts to provide an "infinitely extending" stream. 277/// 278/// Basically, it does what ResizeBitStream does, but it validates 279/// on every write op, so that you never have to worry about overwriting 280/// the buffer. 281class InfiniteBitStream : public ResizeBitStream 282{ 283public: 284 InfiniteBitStream(); 285 ~InfiniteBitStream(); 286 287 /// Ensure we have space for at least upcomingBytes more bytes in the stream. 288 void validate(U32 upcomingBytes); 289 290 /// Reset the stream to zero length (but don't clean memory). 291 void reset(); 292 293 /// Shrink the buffer down to match the actual size of the data. 294 void compact(); 295 296 /// Write us out to a stream... Results in last byte getting padded! 297 void writeToStream(Stream &s); 298 299 virtual void writeBits(S32 bitCount, const void *bitPtr) 300 { 301 validate((bitCount >> 3) + 1); // Add a little safety. 302 BitStream::writeBits(bitCount, bitPtr); 303 } 304 305 virtual bool writeFlag(bool val) 306 { 307 validate(1); // One bit will at most grow our buffer by a byte. 308 return BitStream::writeFlag(val); 309 } 310 311 const U32 getCRC() 312 { 313 // This could be kinda inefficient - BJG 314 return CRC::calculateCRC(getBuffer(), getStreamSize()); 315 } 316}; 317 318//------------------------------------------------------------------------------ 319//-------------------------------------- INLINES 320// 321inline S32 BitStream::getCurPos() const 322{ 323 return bitNum; 324} 325 326inline void BitStream::setCurPos(const U32 in_position) 327{ 328 AssertFatal(in_position < (U32)(bufSize << 3), "Out of range bitposition"); 329 bitNum = S32(in_position); 330} 331 332inline bool BitStream::readFlag() 333{ 334 if(bitNum > maxReadBitNum) 335 { 336 error = true; 337 AssertFatal(false, "Out of range read"); 338 return false; 339 } 340 S32 mask = 1 << (bitNum & 0x7); 341 bool ret = (*(mDataPtr + (bitNum >> 3)) & mask) != 0; 342 bitNum++; 343 return ret; 344} 345 346inline void BitStream::writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd) 347{ 348 AssertFatal(value >= rangeStart && value <= rangeEnd, "Out of bounds value!"); 349 AssertFatal(rangeEnd >= rangeStart, "error, end of range less than start"); 350 351 U32 rangeSize = rangeEnd - rangeStart + 1; 352 U32 rangeBits = getBinLog2(getNextPow2(rangeSize)); 353 354 writeInt(S32(value - rangeStart), S32(rangeBits)); 355} 356 357inline U32 BitStream::readRangedU32(U32 rangeStart, U32 rangeEnd) 358{ 359 AssertFatal(rangeEnd >= rangeStart, "error, end of range less than start"); 360 361 U32 rangeSize = rangeEnd - rangeStart + 1; 362 U32 rangeBits = getBinLog2(getNextPow2(rangeSize)); 363 364 U32 val = U32(readInt(S32(rangeBits))); 365 return val + rangeStart; 366} 367 368inline void BitStream::writeRangedS32( S32 value, S32 min, S32 max ) 369{ 370 value = mClamp( value, min, max ); 371 writeRangedU32( ( value - min ), 0, ( max - min ) ); 372} 373 374inline S32 BitStream::readRangedS32( S32 min, S32 max ) 375{ 376 return readRangedU32( 0, ( max - min ) ) + min; 377} 378 379inline void BitStream::writeRangedF32( F32 value, F32 min, F32 max, U32 numBits ) 380{ 381 value = ( mClampF( value, min, max ) - min ) / ( max - min ); 382 writeInt( (S32)mFloor(value * F32( (1 << numBits) - 1 )), numBits ); 383} 384 385inline F32 BitStream::readRangedF32( F32 min, F32 max, U32 numBits ) 386{ 387 F32 value = (F32)readInt( numBits ); 388 value /= F32( ( 1 << numBits ) - 1 ); 389 return min + value * ( max - min ); 390} 391 392#endif //_BITSTREAM_H_ 393