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