BitPacker.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. //
  19. // Filename: bitpacker.cpp
  20. // Project: wwbitpack.lib
  21. // Author: Tom Spencer-Smith
  22. // Date: June 1998
  23. // Description: Minimal bit encoding
  24. //
  25. #include "bitpacker.h"
  26. #include <string.h> // for memset
  27. #include "wwdebug.h"
  28. //-----------------------------------------------------------------------------
  29. //cBitPacker::cBitPacker(UINT buffer_size) :
  30. cBitPacker::cBitPacker() :
  31. //BufferSize(buffer_size),
  32. BitWritePosition(0),
  33. BitReadPosition(0)
  34. {
  35. //WWASSERT(BufferSize > 0);
  36. //Buffer = new BYTE[BufferSize];
  37. //WWASSERT(Buffer != NULL);
  38. //memset(Buffer, 0, BufferSize);
  39. memset(Buffer, 0, MAX_BUFFER_SIZE);
  40. }
  41. //-----------------------------------------------------------------------------
  42. cBitPacker::~cBitPacker()
  43. {
  44. //delete [] Buffer;
  45. }
  46. //-----------------------------------------------------------------------------
  47. cBitPacker& cBitPacker::operator=(const cBitPacker& rhs)
  48. {
  49. //WWASSERT(BufferSize == rhs.BufferSize);
  50. //memcpy(Buffer, rhs.Buffer, rhs.BufferSize);
  51. memcpy(Buffer, rhs.Buffer, MAX_BUFFER_SIZE);
  52. BitReadPosition = rhs.BitReadPosition;
  53. BitWritePosition = rhs.BitWritePosition;
  54. return * this;
  55. }
  56. //-----------------------------------------------------------------------------
  57. //
  58. // This method needs optimization
  59. //
  60. // 02-14-2002 Jani: Optimized the code somewhat. Note that the old code reverted
  61. // the bit order and the new one doesn't, so the versions are not compatible.
  62. // If you use optimized Add_Bits() you need to also use optimize Get_Bits().
  63. //
  64. void cBitPacker::Add_Bits(ULONG value, UINT num_bits)
  65. {
  66. //
  67. // N.B. Presently you cannot use this class with an atomic type of more
  68. // than 4 bytes, such as a double. Hopefully you would be using a float
  69. // instead anyway.
  70. //
  71. #if 0 // Old version
  72. WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
  73. ULONG mask = 1 << (num_bits - 1);
  74. while (mask > 0) {
  75. //WWASSERT(BitWritePosition < BufferSize * 8);
  76. WWASSERT(BitWritePosition < MAX_BUFFER_SIZE * 8);
  77. UINT byte_num = BitWritePosition / 8;
  78. UINT bit_offset = BitWritePosition % 8;
  79. bool bit_value = (value & mask) != 0;
  80. Buffer[byte_num] |= bit_value << bit_offset;
  81. BitWritePosition++;
  82. mask >>= 1;
  83. }
  84. #else // New faster version
  85. // Verify that we're not writing over buffer
  86. WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
  87. WWASSERT(BitWritePosition+num_bits <= MAX_BUFFER_SIZE * 8);
  88. // Fill the remaining bits of the write byte first
  89. UINT byte_num = BitWritePosition >> 3;
  90. UINT bit_offset = BitWritePosition & 0x7;
  91. BitWritePosition+=num_bits; // Advance the write position
  92. // If write buffer is not byte aligned, write the remaining bits first
  93. value <<= 32-num_bits;
  94. if (bit_offset) {
  95. UINT bit_count = 8 - bit_offset;
  96. if (bit_count>num_bits) bit_count=num_bits;
  97. ULONG bit_value = value;
  98. value <<= bit_count; // Remove the copied bits
  99. num_bits -= bit_count;
  100. bit_value >>= (24+bit_offset);
  101. Buffer[byte_num++] |= bit_value;
  102. }
  103. // Write the rest of the data as bytes
  104. if (num_bits>8) {
  105. for (unsigned a=0;a<num_bits;a+=8) {
  106. Buffer[byte_num++]=unsigned char(value>>24);
  107. value<<=8;
  108. }
  109. }
  110. else {
  111. Buffer[byte_num]=unsigned char(value>>24);
  112. }
  113. #endif
  114. }
  115. //-----------------------------------------------------------------------------
  116. //
  117. // This method needs optimization
  118. // 02-14-2002 Jani: Optimized. See Add_Bits() for notes.
  119. //
  120. void cBitPacker::Get_Bits(ULONG & value, UINT num_bits)
  121. {
  122. #if 0 // Old version
  123. WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
  124. value = 0;
  125. for (int bit = num_bits - 1; bit >= 0; bit--) {
  126. //WWASSERT(BitReadPosition < BufferSize * 8);
  127. WWASSERT(BitReadPosition < MAX_BUFFER_SIZE * 8);
  128. WWASSERT(BitReadPosition < BitWritePosition);
  129. UINT byte_num = BitReadPosition / 8;
  130. UINT bit_offset = BitReadPosition % 8;
  131. bool b = (Buffer[byte_num] & (1 << bit_offset)) != 0;
  132. value += (b << bit);
  133. BitReadPosition++;
  134. }
  135. #else // New faster version
  136. // Verify that we're not reading over buffer or write pointer
  137. WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
  138. WWASSERT(BitReadPosition+num_bits <= MAX_BUFFER_SIZE * 8);
  139. WWASSERT(BitReadPosition+num_bits <= BitWritePosition);
  140. UINT read_len=num_bits;
  141. UINT byte_num = BitReadPosition / 8;
  142. UINT bit_offset = BitReadPosition % 8;
  143. BitReadPosition += num_bits;
  144. UINT bit_count = 8 - bit_offset;
  145. if (bit_count>num_bits) bit_count=num_bits;
  146. value = (ULONG(Buffer[byte_num++]) << (bit_offset+24));
  147. num_bits-=bit_count;
  148. for (int shift=24-bit_count;shift>0;shift-=8,num_bits-=8) value|=unsigned(Buffer[byte_num++]) << shift;
  149. if (num_bits>0) value|=Buffer[byte_num++]>>(-shift);
  150. value >>= 32-read_len;
  151. #endif
  152. }
  153. //-----------------------------------------------------------------------------
  154. //
  155. // This method is only for use by a packet class when data is received.
  156. //
  157. void cBitPacker::Set_Bit_Write_Position(UINT position)
  158. {
  159. //WWASSERT(position <= BufferSize * 8);
  160. WWASSERT(position <= MAX_BUFFER_SIZE * 8);
  161. BitWritePosition = position;
  162. }
  163. /*
  164. //-----------------------------------------------------------------------------
  165. void cBitPacker::Increment_Bit_Position(int num_bits)
  166. {
  167. WWASSERT(num_bits >= 0);
  168. for (int i = 0; i < num_bits; i++) {
  169. Advance_Bit_Position();
  170. NumBits++;
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. UINT cBitPacker::Get_Compressed_Size_Bytes() const
  175. {
  176. return (int) ceil(BitWritePosition / 8.0f);
  177. }
  178. //-----------------------------------------------------------------------------
  179. inline void cBitPacker::Advance_Bit_Position()
  180. {
  181. BitWritePosition++;
  182. //
  183. // If the following assert hits then our buffer is not large enough.
  184. // We can advance BitWritePosition one bit past the end of the buffer, but
  185. // we cannot write there.
  186. //
  187. //WWASSERT(BitWritePosition < BufferSize * 8);
  188. WWASSERT(BitWritePosition <= BufferSize * 8);
  189. }
  190. */