bitStream.h

Engine/source/core/stream/bitStream.h

More...

Classes:

class

This class acts to provide an "infinitely extending" stream.

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