1
2//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
3//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
4#pragma once
5
6#include "Prerequisites/BsPrerequisitesUtil.h"
7#include "Math/BsMath.h"
8#include "Math/BsQuaternion.h"
9#include "Math/BsVector3.h"
10#include "Utility/BsBitwise.h"
11
12namespace bs
13{
14 /** @addtogroup General
15 * @{
16 */
17
18 /**
19 * Allows encoding/decoding of types into a stream of bits. Supports various methods of storing data in a compact form.
20 * The bitstream can manage its internal memory or a user can provide an external source of data. If using internal
21 * memory the bitstream will automatically grow the memory storage as needed.
22 *
23 * The stream keeps an internal cursor that represents the bit at which to perform read & write operations.
24 * Read & write operations will operate at the current cursor location and the cursor will be advanced by the number of
25 * bits read or written. If writing outside of range the internal memory buffer will be automatically expanded, except
26 * when external memory buffer is used, in which case it is undefined behaviour. Reading outside of range is always
27 * undefined behaviour.
28 */
29 class Bitstream
30 {
31 using QuantType = uint8_t;
32 public:
33 /**
34 * Initializes an empty bitstream. As data is written the stream will grow its internal memory storage
35 * automatically.
36 */
37 Bitstream() = default;
38
39 /**
40 * Initializes a bitstream with some initial capacity. If more bytes than capacity is written, the bitstream will
41 * grow its internal memory storage.
42 *
43 * @param[in] capacity Number of bytes to initially allocate for the internal memory storage.
44 */
45 Bitstream(uint32_t capacity);
46
47 /**
48 * Initializes a bitstream with external data storage. The bitstream will not manage internal memory and will not
49 * grow memory storage if capacity is exceeded. The user is responsible for keeping track and not writing outside
50 * of buffer range.
51 *
52 * @param[in] data Address of the external memory buffer. The user is responsible of keeping this memory alive
53 * for the lifetime of the bitstream, as well as releasing it. Must have enough capacity to
54 * store @p count bits.
55 * @param[in] count Size of the provided data, in bits.
56 */
57 Bitstream(QuantType* data, uint32_t count);
58
59 ~Bitstream();
60
61 /**
62 * Writes bits from the provided buffer into the stream at the current cursor location and advances the cursor.
63 *
64 * @param[in] data Buffer to write the data from. Must have enough capacity to store @p count bits.
65 * @param[in] count Number of bits to write.
66 */
67 void writeBits(const QuantType* data, uint32_t count);
68
69 /**
70 * Reads bits from the stream into the provided buffer from the current cursor location and advances the cursor.
71 *
72 * @param[out] data Buffer to read the data from. Must have enough capacity to store @p count bits.
73 * @param[in] count Number of bits to read.
74 */
75 void readBits(QuantType* data, uint32_t count);
76
77 /**
78 * Writes the provided data into the stream at the current cursor location and advances the cursor.
79 *
80 * @param[in] value Data to write.
81 */
82 template<class T>
83 void write(const T& value);
84
85 /**
86 * Reads bits from the stream and writes them into the provided object. Data is read from the current cursor
87 * location and advances the cursor.
88 *
89 * @param[out] value Object to initialize with the read bits.
90 */
91 template<class T>
92 void read(T& value);
93
94 /** @copydoc write(const T&) */
95 void write(const bool& value);
96
97 /** @copydoc read(T&) */
98 void read(bool& value);
99
100 /** @copydoc write(const T&) */
101 void write(const String& value);
102
103 /** @copydoc read(T&) */
104 void read(String& value);
105
106 /**
107 * Checks if the provided value differs from the last provided value, and if they are equivalent writes just a
108 * single bit signifying no change. Otherwise the value is encoded as if calling write().
109 */
110 template<class T>
111 void writeDelta(const T& value, const T& lastValue);
112
113 /** Reads the data written by writeDelta() from the current cursor location and advances the cursor. */
114 template<class T>
115 void readDelta(T& value, const T& lastValue);
116
117 /** @copydoc writeDelta(const T&, const T&) */
118 void writeDelta(bool value, bool lastValue);
119
120 /** @copydoc readDelta(T&, const T&) */
121 void readDelta(bool& value, bool lastValue);
122
123 /**
124 * Encodes a 32-bit integer value as a base-128 varint and writes it to the stream. Write is performed at the
125 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
126 * more bytes, where smaller values use less bytes.
127 */
128 void writeVarInt(uint32_t value);
129
130 /**
131 * Encodes a 32-bit integer value as a base-128 varint and writes it to the stream. Write is performed at the
132 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
133 * more bytes, where smaller values use less bytes.
134 */
135 void writeVarInt(int32_t value);
136
137 /**
138 * Encodes a 64-bit integer value as a base-128 varint and writes it to the stream. Write is performed at the
139 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
140 * more bytes, where smaller values use less bytes.
141 */
142 void writeVarInt(uint64_t value);
143
144 /**
145 * Encodes a 64-bit integer value as a base-128 varint and writes it to the stream. Write is performed at the
146 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
147 * more bytes, where smaller values use less bytes.
148 */
149 void writeVarInt(int64_t value);
150
151 /**
152 * Decodes a 32-bit integer value encoded as a base-128 varint from the stream. Read is performed at the
153 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
154 * more bytes, where smaller values use less bytes.
155 */
156 void readVarInt(uint32_t& value);
157
158 /**
159 * Decodes a 32-bit integer value encoded as a base-128 varint from the stream. Read is performed at the
160 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
161 * more bytes, where smaller values use less bytes.
162 */
163 void readVarInt(int32_t& value);
164
165 /**
166 * Decodes a 32-bit integer value encoded as a base-128 varint from the stream. Read is performed at the
167 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
168 * more bytes, where smaller values use less bytes.
169 */
170 void readVarInt(uint64_t& value);
171
172 /**
173 * Decodes a 32-bit integer value encoded as a base-128 varint from the stream. Read is performed at the
174 * current cursor location and advances the cursor. Varints are a method of serializing integers using one or
175 * more bytes, where smaller values use less bytes.
176 */
177 void readVarInt(int64_t& value);
178
179 /**
180 * Checks if the provided value differs from the last provided value, and if they are equivalent writes just a
181 * single bit signifying no change. Otherwise the value is encoded as if calling writeVarInt().
182 */
183 template<class T>
184 void writeVarIntDelta(const T& value, const T& lastValue);
185
186 /** Reads the data written by writeVarIntDelta() from the current cursor location and advances the cursor. */
187 template<class T>
188 void readVarIntDelta(T& value, const T& lastValue);
189
190 /**
191 * Encodes a float in range [0, 1] into a fixed point representation using a specific number of bits, and writes it
192 * to the stream. Write is performed at the current cursor location and advances the cursor.
193 */
194 void writeNorm(float value, uint32_t bits = 16);
195
196 /**
197 * Decodes a float encoded using writeNorm(float, uint32_t). Read is performed at the current cursor location and
198 * advances the cursor. Same number of bits need to be used as when the float was encoded.
199 */
200 void readNorm(float& value, uint32_t bits = 16);
201
202 /**
203 * Encodes a 3D vector with individual components in range [-1, 1] into a fixed point representation where each
204 * component uses a specific number of bits, and writes it to the stream. Write is performed at the current cursor
205 * location and advances the cursor.
206 */
207 void writeNorm(const Vector3& value, uint32_t bits = 16);
208
209 /**
210 * Decodes a 3D vector encoded using writeNorm(Vector3, uint32_t). Read is performed at the current cursor location
211 * and advances the cursor. Same number of bits need to be used as when the float was encoded.
212 */
213 void readNorm(Vector3& value, uint32_t bits = 16);
214
215 /**
216 * Encodes a quaternion with individual components in range [-1, 1] into a fixed point representation where each
217 * component uses a specific number of bits, and writes it to the stream. Write is performed at the current cursor
218 * location and advances the cursor.
219 */
220 void writeNorm(const Quaternion& value, uint32_t bits = 16);
221
222 /**
223 * Decodes a quaternion encoded using writeNorm(Quaternion, uint32_t). Read is performed at the current cursor
224 * location and advances the cursor. Same number of bits need to be used as when the float was encoded.
225 */
226 void readNorm(Quaternion& value, uint32_t bits = 16);
227
228 /**
229 * Checks if the provided value differs from the last provided value, and if they are equivalent writes just a
230 * single bit signifying no change. Otherwise the value is encoded as if calling writeNorm().
231 */
232 template<class T>
233 void writeNormDelta(const T& value, const T& lastValue, uint32_t bits = 16);
234
235 /** Reads the data written by writeNormDelta() from the current cursor location and advances the cursor. */
236 template<class T>
237 void readNormDelta(T& value, const T& lastValue, uint32_t bits = 16);
238
239 /**
240 * Encodes an integer in a specific range, using the range the reduce the number of bits required, and writes it
241 * to the stream. Write is performed at the current cursor location and advances the cursor.
242 */
243 template<class T>
244 void writeRange(const T& value, const T& min, const T& max);
245
246 /**
247 * Decodes an integer encoded using writeRange(const T&, const T&, const T&). Read is performed at the current
248 * cursor location and advances the cursor. Same needs to be used as when the value was encoded.
249 */
250 template<class T>
251 void readRange(T& value, const T& min, const T& max);
252
253 /**
254 * Checks if the provided value differs from the last provided value, and if they are equivalent writes just a
255 * single bit signifying no change. Otherwise the value is encoded as if calling
256 * writeRange(const T&, const T&, const T&).
257 */
258 template<class T>
259 void writeRangeDelta(const T& value, const T& lastValue, const T& min, const T& max);
260
261 /**
262 * Reads the data written by writeRangeDelta(const T&, const T&, const T&, const T&) from the current cursor
263 * location and advances the cursor.
264 */
265 template<class T>
266 void readRangeDelta(T& value, const T& lastValue, const T& min, const T& max);
267
268 /**
269 * Encodes a float in a specific range into a fixed point representation using a specific number of bits, and
270 * writes it to the stream. Write is performed at the current cursor location and advances the cursor.
271 */
272 void writeRange(float value, float min, float max, uint32_t bits = 16);
273
274 /**
275 * Decodes a float encoded using writeRange(float, float, float, uint32_t). Read is performed at the current cursor
276 * location and advances the cursor. Same number of bits, and the same range needs to be used as when the float was
277 * encoded.
278 */
279 void readRange(float& value, float min, float max, uint32_t bits = 16);
280
281 /**
282 * Checks if the provided value differs from the last provided value, and if they are equivalent writes just a
283 * single bit signifying no change. Otherwise the value is encoded as if calling
284 * writeRange(float, float, float, uint32_t).
285 */
286 void writeRangeDelta(float value, float lastValue, float min, float max, uint32_t bits = 16);
287
288 /**
289 * Reads the data written by writeRangeDelta(float, float, float, float, uint32_t) from the current cursor
290 * location and advances the cursor.
291 */
292 void readRangeDelta(float& value, float lastValue, float min, float max, uint32_t bits = 16);
293
294 /**
295 * Skip a defined number of bits, moving the read/write cursor by this amount. This can also be a negative value,
296 * in which case the file pointer rewinds a defined number of bits. Note the cursor can never skip past the
297 * capacity of the buffer, and will be clamped.
298 */
299 void skip(int32_t count);
300
301 /**
302 * Repositions the read/write cursor to the specified bit. Note the cursor can never skip past the capacity
303 * of the buffer, and will be clamped.
304 */
305 void seek(uint32_t pos);
306
307 /**
308 * Aligns the read/write cursor to a byte boundary. @p count determines the alignment in bytes. Note the
309 * requested alignment might not be achieved if count > 1 and it would move the cursor past the capacity of the
310 * buffer, as the cursor will be clamped to buffer end regardless of alignment.
311 */
312 void align(uint32_t count = 1);
313
314 /** Returns the current read/write cursor position, in bits. */
315 uint32_t tell() const { return mCursor; }
316
317 /** Returns true if the stream has reached the end. */
318 bool eof() const { return mCursor >= mNumBits; }
319
320 /** Returns the total number of bits available in the stream. */
321 uint32_t size() const { return mNumBits; }
322
323 /** Returns the total number of bits the stream can store without needing to allocate more memory. */
324 uint32_t capacity() const { return mMaxBits; }
325
326 /** Returns the internal data buffer. */
327 QuantType* data() const { return mData; }
328
329 private:
330 static constexpr uint32_t BYTES_PER_QUANT = sizeof(QuantType);
331 static constexpr uint32_t BITS_PER_QUANT = BYTES_PER_QUANT * 8;
332 static constexpr uint32_t BITS_PER_QUANT_LOG2 = Bitwise::bitsLog2(BITS_PER_QUANT);
333
334 /** Checks if the internal memory buffer needs to grow in order to accomodate @p numBits bits. */
335 void reallocIfNeeded(uint32_t numBits);
336
337 /** Reallocates the internal buffer making enough room for @p numBits (rounded to a multiple of BYTES_PER_QUANT. */
338 void realloc(uint32_t numBits);
339
340 QuantType* mData = nullptr;
341 uint32_t mMaxBits = 0;
342 uint32_t mNumBits = 0;
343 bool mOwnsMemory = true;
344
345 uint32_t mCursor = 0;
346 };
347
348 /** @} */
349
350 /** @addtogroup Implementation
351 * @{
352 */
353
354 inline Bitstream::Bitstream(uint32_t capacity)
355 {
356 realloc(capacity * 8);
357 }
358
359 inline Bitstream::Bitstream(QuantType* data, uint32_t count)
360 : mData(data), mMaxBits(count), mNumBits(count), mOwnsMemory(false) { }
361
362 inline Bitstream::~Bitstream()
363 {
364 if (mData && mOwnsMemory)
365 bs_free(mData);
366 }
367
368 inline void Bitstream::writeBits(const QuantType* data, uint32_t count)
369 {
370 if (count == 0)
371 return;
372
373 uint32_t newCursor = mCursor + count;
374 reallocIfNeeded(newCursor);
375
376 uint32_t destBitsMod = mCursor & (BITS_PER_QUANT - 1);
377 uint32_t destQuant = mCursor >> BITS_PER_QUANT_LOG2;
378 uint32_t destMask = (1 << destBitsMod) - 1;
379
380 // If destination is aligned, memcpy everything except the last quant (unless it is also aligned)
381 if (destBitsMod == 0)
382 {
383 uint32_t numQuants = count >> BITS_PER_QUANT_LOG2;
384 memcpy(&mData[destQuant], data, numQuants * BYTES_PER_QUANT);
385
386 data += numQuants;
387 count -= numQuants * BITS_PER_QUANT;
388 destQuant += numQuants;
389 }
390
391 // Write remaining bits (or all bits if destination wasn't aligned)
392 while (count > 0)
393 {
394 QuantType quant = *data;
395 data++;
396
397 mData[destQuant] = (quant << destBitsMod) | (mData[destQuant] & destMask);
398
399 uint32_t writtenBits = BITS_PER_QUANT - destBitsMod;
400 if (count > writtenBits)
401 mData[destQuant + 1] = (quant >> writtenBits) | (mData[destQuant + 1] & ~destMask);
402
403 destQuant++;
404 count -= std::min(BITS_PER_QUANT, count);
405 }
406
407 mCursor = newCursor;
408 mNumBits = std::max(mNumBits, newCursor);
409 }
410
411 inline void Bitstream::readBits(QuantType* data, uint32_t count)
412 {
413 if (count == 0)
414 return;
415
416 assert((mCursor + count) <= mNumBits);
417
418 uint32_t newCursor = mCursor + count;
419 uint32_t srcBitsMod = mCursor & (BITS_PER_QUANT - 1);
420 uint32_t srcQuant = mCursor >> BITS_PER_QUANT_LOG2;
421
422 // If source is aligned, memcpy everything except the last quant (unless it is also aligned)
423 if (srcBitsMod == 0)
424 {
425 uint32_t numQuants = count >> BITS_PER_QUANT_LOG2;
426 memcpy(data, &mData[srcQuant], numQuants * BYTES_PER_QUANT);
427
428 data += numQuants;
429 count -= numQuants * BITS_PER_QUANT;
430 srcQuant += numQuants;
431 }
432
433 // Read remaining bits (or all bits if source wasn't aligned)
434 while (count > 0)
435 {
436 QuantType& quant = *data;
437 data++;
438
439 quant = 0;
440 quant |= mData[srcQuant] >> srcBitsMod;
441
442 uint32_t readBits = BITS_PER_QUANT - srcBitsMod;
443 if (count > readBits)
444 quant |= mData[srcQuant + 1] << readBits;
445
446 srcQuant++;
447 count -= std::min(BITS_PER_QUANT, count);
448 }
449
450 mCursor = newCursor;
451 }
452
453 template <class T>
454 void Bitstream::write(const T& value)
455 {
456 writeBits((QuantType*)&value, sizeof(value) * 8);
457 }
458
459 template <class T>
460 void Bitstream::read(T& value)
461 {
462 QuantType* temp = (QuantType*)&value;
463 readBits(temp, sizeof(value) * 8);
464 }
465
466 inline void Bitstream::write(const bool& value)
467 {
468 reallocIfNeeded(mCursor + 1);
469
470 uint32_t destBitsMod = mCursor & (BITS_PER_QUANT - 1);
471 uint32_t destQuant = mCursor >> BITS_PER_QUANT_LOG2;
472
473 if (value)
474 mData[destQuant] |= 1U << destBitsMod;
475 else
476 mData[destQuant] &= ~(1U << destBitsMod);
477
478 mCursor++;
479 mNumBits = std::max(mNumBits, mCursor);
480 }
481
482 inline void Bitstream::read(bool& value)
483 {
484 assert((mCursor + 1) <= mNumBits);
485
486 uint32_t srcBitsMod = mCursor & (BITS_PER_QUANT - 1);
487 uint32_t srcQuant = mCursor >> BITS_PER_QUANT_LOG2;
488
489 value = (mData[srcQuant] >> srcBitsMod) & 0x1;
490 mCursor++;
491 }
492
493 inline void Bitstream::write(const String& value)
494 {
495 uint32_t length = (uint32_t)value.size();
496 writeVarInt(length);
497 writeBits((QuantType*)value.data(), length * 8);
498 }
499
500 inline void Bitstream::read(String& value)
501 {
502 uint32_t length;
503 readVarInt(length);
504
505 value.resize(length);
506
507 QuantType* temp = (QuantType*)value.data();
508 readBits(temp, length * 8);
509 }
510
511 template <class T>
512 void Bitstream::writeDelta(const T& value, const T& lastValue)
513 {
514 if(value == lastValue)
515 write(true);
516 else
517 {
518 write(false);
519 write(value);
520 }
521 }
522
523 template <class T>
524 void Bitstream::readDelta(T& value, const T& lastValue)
525 {
526 bool clean;
527 read(clean);
528
529 if(clean)
530 value = lastValue;
531 else
532 read(value);
533 }
534
535 inline void Bitstream::writeDelta(bool value, bool lastValue)
536 {
537 write(value);
538 }
539
540 inline void Bitstream::readDelta(bool& value, bool lastValue)
541 {
542 read(value);
543 }
544
545 inline void Bitstream::writeVarInt(uint32_t value)
546 {
547 uint8_t output[5];
548 uint32_t count = Bitwise::encodeVarInt(value, output);
549
550 writeBits(output, count * 8);
551 }
552
553 inline void Bitstream::writeVarInt(int32_t value)
554 {
555 uint8_t output[5];
556 uint32_t count = Bitwise::encodeVarInt(value, output);
557
558 writeBits(output, count * 8);
559 }
560
561 inline void Bitstream::writeVarInt(uint64_t value)
562 {
563 uint8_t output[10];
564 uint32_t count = Bitwise::encodeVarInt(value, output);
565
566 writeBits(output, count * 8);
567 }
568
569 inline void Bitstream::writeVarInt(int64_t value)
570 {
571 uint8_t output[10];
572 uint32_t count = Bitwise::encodeVarInt(value, output);
573
574 writeBits(output, count * 8);
575 }
576
577 inline void Bitstream::readVarInt(uint32_t& value)
578 {
579 uint8_t output[5];
580 for(uint32_t i = 0; i < 5; i++)
581 {
582 readBits(&output[i], 8);
583 if((output[i] & 0x80) == 0)
584 break;
585 }
586
587 Bitwise::decodeVarInt(value, output, 5);
588 }
589
590 inline void Bitstream::readVarInt(int32_t& value)
591 {
592 uint8_t output[5];
593 for(uint32_t i = 0; i < 5; i++)
594 {
595 readBits(&output[i], 8);
596 if((output[i] & 0x80) == 0)
597 break;
598 }
599
600 Bitwise::decodeVarInt(value, output, 5);
601 }
602
603 inline void Bitstream::readVarInt(uint64_t& value)
604 {
605 uint8_t output[10];
606 for(uint32_t i = 0; i < 10; i++)
607 {
608 readBits(&output[i], 8);
609 if((output[i] & 0x80) == 0)
610 break;
611 }
612
613 Bitwise::decodeVarInt(value, output, 10);
614 }
615
616 inline void Bitstream::readVarInt(int64_t& value)
617 {
618 uint8_t output[10];
619 for(uint32_t i = 0; i < 10; i++)
620 {
621 readBits(&output[i], 8);
622 if((output[i] & 0x80) == 0)
623 break;
624 }
625
626 Bitwise::decodeVarInt(value, output, 10);
627 }
628
629 template <class T>
630 void Bitstream::writeVarIntDelta(const T& value, const T& lastValue)
631 {
632 if(value == lastValue)
633 write(true);
634 else
635 {
636 write(false);
637 writeVarInt(value);
638 }
639 }
640
641 template <class T>
642 void Bitstream::readVarIntDelta(T& value, const T& lastValue)
643 {
644 bool clean;
645 read(clean);
646
647 if(clean)
648 value = lastValue;
649 else
650 readVarInt(value);
651 }
652
653 inline void Bitstream::writeNorm(float value, uint32_t bits)
654 {
655 uint32_t encodedVal = Bitwise::unormToUint(value, bits);
656 writeBits((QuantType*)&encodedVal, bits);
657 }
658
659 inline void Bitstream::readNorm(float& value, uint32_t bits)
660 {
661 uint32_t encodedVal = 0;
662 readBits((QuantType*)&encodedVal, bits);
663 value = Bitwise::uintToUnorm(encodedVal, bits);
664 }
665
666 inline void Bitstream::writeNorm(const Vector3& value, uint32_t bits)
667 {
668 writeRange(value.x, -1.0f, 1.0f, bits);
669 writeRange(value.y, -1.0f, 1.0f, bits);
670 writeRange(value.z, -1.0f, 1.0f, bits);
671 }
672
673 inline void Bitstream::readNorm(Vector3& value, uint32_t bits)
674 {
675 readRange(value.x, -1.0f, 1.0f, bits);
676 readRange(value.y, -1.0f, 1.0f, bits);
677 readRange(value.z, -1.0f, 1.0f, bits);
678 }
679
680 inline void Bitstream::writeNorm(const Quaternion& value, uint32_t bits)
681 {
682 writeRange(value.x, -1.0f, 1.0f, bits);
683 writeRange(value.y, -1.0f, 1.0f, bits);
684 writeRange(value.z, -1.0f, 1.0f, bits);
685 writeRange(value.w, -1.0f, 1.0f, bits);
686 }
687
688 inline void Bitstream::readNorm(Quaternion& value, uint32_t bits)
689 {
690 readRange(value.x, -1.0f, 1.0f, bits);
691 readRange(value.y, -1.0f, 1.0f, bits);
692 readRange(value.z, -1.0f, 1.0f, bits);
693 readRange(value.w, -1.0f, 1.0f, bits);
694 }
695
696 template <class T>
697 void Bitstream::writeNormDelta(const T& value, const T& lastValue, uint32_t bits)
698 {
699 if(value == lastValue)
700 write(true);
701 else
702 {
703 write(false);
704 writeNorm(value, bits);
705 }
706 }
707
708 template <class T>
709 void Bitstream::readNormDelta(T& value, const T& lastValue, uint32_t bits)
710 {
711 bool clean;
712 read(clean);
713
714 if(clean)
715 value = lastValue;
716 else
717 readNorm(value, bits);
718 }
719
720
721 template <class T>
722 void Bitstream::writeRange(const T& value, const T& min, const T& max)
723 {
724 T range = max - min;
725 uint32_t bits = Bitwise::mostSignificantBit(range) + 1;
726
727 T rangeVal = value - min;
728 writeBits((QuantType*)&rangeVal, bits);
729 }
730
731 template <class T>
732 void Bitstream::readRange(T& value, const T& min, const T& max)
733 {
734 T range = max - min;
735 uint32_t bits = Bitwise::mostSignificantBit(range) + 1;
736
737 value = 0;
738 readBits((QuantType*)&value, bits);
739 value += min;
740 }
741
742 template <class T>
743 void Bitstream::writeRangeDelta(const T& value, const T& lastValue, const T& min, const T& max)
744 {
745 if(value == lastValue)
746 write(true);
747 else
748 {
749 write(false);
750 writeRange(value, min, max);
751 }
752 }
753
754 template <class T>
755 void Bitstream::readRangeDelta(T& value, const T& lastValue, const T& min, const T& max)
756 {
757 bool clean;
758 read(clean);
759
760 if(clean)
761 value = lastValue;
762 else
763 readRange(value, min, max);
764 }
765
766 inline void Bitstream::writeRange(float value, float min, float max, uint32_t bits)
767 {
768 float pct = Math::clamp01((value - min)/(max - min));
769 writeNorm(pct, bits);
770 }
771
772 inline void Bitstream::readRange(float& value, float min, float max, uint32_t bits)
773 {
774 float pct;
775 readNorm(pct, bits);
776
777 value = min + (max - min) * pct;
778 }
779
780 inline void Bitstream::writeRangeDelta(float value, float lastValue, float min, float max, uint32_t bits)
781 {
782 if(value == lastValue)
783 write(true);
784 else
785 {
786 write(false);
787 writeRange(value, min, max, bits);
788 }
789 }
790
791 inline void Bitstream::readRangeDelta(float& value, float lastValue, float min, float max, uint32_t bits)
792 {
793 bool clean;
794 read(clean);
795
796 if(clean)
797 value = lastValue;
798 else
799 readRange(value, min, max, bits);
800 }
801
802 inline void Bitstream::skip(int32_t count)
803 {
804 mCursor = (uint32_t)Math::clamp((int32_t)mCursor + count, 0, (int32_t)mMaxBits);
805 }
806
807 inline void Bitstream::seek(uint32_t pos)
808 {
809 mCursor = std::min(pos, mMaxBits);
810 }
811
812 inline void Bitstream::align(uint32_t count)
813 {
814 if (count == 0)
815 return;
816
817 uint32_t bits = count * 8;
818 skip(bits - (((mCursor - 1) & (bits - 1)) + 1));
819 }
820
821 inline void Bitstream::reallocIfNeeded(uint32_t numBits)
822 {
823 if (numBits > mMaxBits)
824 {
825 if (mOwnsMemory)
826 {
827 // Grow
828 const uint32_t newMaxBits = numBits + 4 * BITS_PER_QUANT + numBits / 2;
829 realloc(newMaxBits);
830 }
831 else
832 {
833 // Caller accessing bits outside of external memory range
834 assert(false);
835 }
836 }
837 }
838
839 inline void Bitstream::realloc(uint32_t numBits)
840 {
841 numBits = Math::divideAndRoundUp(numBits, BITS_PER_QUANT) * BITS_PER_QUANT;
842
843 if (numBits != mMaxBits)
844 {
845 assert(numBits > mMaxBits);
846
847 const uint32_t numQuants = Math::divideAndRoundUp(numBits, BITS_PER_QUANT);
848
849 // Note: Eventually add support for custom allocators
850 auto buffer = bs_allocN<uint8_t>(numQuants);
851 if (mData)
852 {
853 const uint32_t numBytes = Math::divideAndRoundUp(mMaxBits, BITS_PER_QUANT) * BYTES_PER_QUANT;
854 memcpy(buffer, mData, numBytes);
855 bs_free(mData);
856 }
857
858 mData = buffer;
859 mMaxBits = numBits;
860 }
861 }
862}
863