| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- //
- // Filename: bitpacker.cpp
- // Project: wwbitpack.lib
- // Author: Tom Spencer-Smith
- // Date: June 1998
- // Description: Minimal bit encoding
- //
- #include "bitpacker.h"
- #include <string.h> // for memset
- #include "wwdebug.h"
- //-----------------------------------------------------------------------------
- //cBitPacker::cBitPacker(UINT buffer_size) :
- cBitPacker::cBitPacker() :
- //BufferSize(buffer_size),
- BitWritePosition(0),
- BitReadPosition(0)
- {
- //WWASSERT(BufferSize > 0);
- //Buffer = new BYTE[BufferSize];
- //WWASSERT(Buffer != NULL);
- //memset(Buffer, 0, BufferSize);
- memset(Buffer, 0, MAX_BUFFER_SIZE);
- }
- //-----------------------------------------------------------------------------
- cBitPacker::~cBitPacker()
- {
- //delete [] Buffer;
- }
- //-----------------------------------------------------------------------------
- cBitPacker& cBitPacker::operator=(const cBitPacker& rhs)
- {
- //WWASSERT(BufferSize == rhs.BufferSize);
- //memcpy(Buffer, rhs.Buffer, rhs.BufferSize);
- memcpy(Buffer, rhs.Buffer, MAX_BUFFER_SIZE);
- BitReadPosition = rhs.BitReadPosition;
- BitWritePosition = rhs.BitWritePosition;
- return * this;
- }
- //-----------------------------------------------------------------------------
- //
- // This method needs optimization
- //
- // 02-14-2002 Jani: Optimized the code somewhat. Note that the old code reverted
- // the bit order and the new one doesn't, so the versions are not compatible.
- // If you use optimized Add_Bits() you need to also use optimize Get_Bits().
- //
- void cBitPacker::Add_Bits(ULONG value, UINT num_bits)
- {
- //
- // N.B. Presently you cannot use this class with an atomic type of more
- // than 4 bytes, such as a double. Hopefully you would be using a float
- // instead anyway.
- //
- #if 0 // Old version
- WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
- ULONG mask = 1 << (num_bits - 1);
- while (mask > 0) {
- //WWASSERT(BitWritePosition < BufferSize * 8);
- WWASSERT(BitWritePosition < MAX_BUFFER_SIZE * 8);
- UINT byte_num = BitWritePosition / 8;
- UINT bit_offset = BitWritePosition % 8;
- bool bit_value = (value & mask) != 0;
- Buffer[byte_num] |= bit_value << bit_offset;
- BitWritePosition++;
- mask >>= 1;
- }
- #else // New faster version
- // Verify that we're not writing over buffer
- WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
- WWASSERT(BitWritePosition+num_bits <= MAX_BUFFER_SIZE * 8);
- // Fill the remaining bits of the write byte first
- UINT byte_num = BitWritePosition >> 3;
- UINT bit_offset = BitWritePosition & 0x7;
- BitWritePosition+=num_bits; // Advance the write position
- // If write buffer is not byte aligned, write the remaining bits first
- value <<= 32-num_bits;
- if (bit_offset) {
- UINT bit_count = 8 - bit_offset;
- if (bit_count>num_bits) bit_count=num_bits;
- ULONG bit_value = value;
- value <<= bit_count; // Remove the copied bits
- num_bits -= bit_count;
- bit_value >>= (24+bit_offset);
- Buffer[byte_num++] |= bit_value;
- }
- // Write the rest of the data as bytes
- if (num_bits>8) {
- for (unsigned a=0;a<num_bits;a+=8) {
- Buffer[byte_num++]=unsigned char(value>>24);
- value<<=8;
- }
- }
- else {
- Buffer[byte_num]=unsigned char(value>>24);
- }
- #endif
- }
- //-----------------------------------------------------------------------------
- //
- // This method needs optimization
- // 02-14-2002 Jani: Optimized. See Add_Bits() for notes.
- //
- void cBitPacker::Get_Bits(ULONG & value, UINT num_bits)
- {
- #if 0 // Old version
- WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
- value = 0;
- for (int bit = num_bits - 1; bit >= 0; bit--) {
- //WWASSERT(BitReadPosition < BufferSize * 8);
- WWASSERT(BitReadPosition < MAX_BUFFER_SIZE * 8);
- WWASSERT(BitReadPosition < BitWritePosition);
- UINT byte_num = BitReadPosition / 8;
- UINT bit_offset = BitReadPosition % 8;
- bool b = (Buffer[byte_num] & (1 << bit_offset)) != 0;
- value += (b << bit);
- BitReadPosition++;
- }
- #else // New faster version
- // Verify that we're not reading over buffer or write pointer
- WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
- WWASSERT(BitReadPosition+num_bits <= MAX_BUFFER_SIZE * 8);
- WWASSERT(BitReadPosition+num_bits <= BitWritePosition);
- UINT read_len=num_bits;
- UINT byte_num = BitReadPosition / 8;
- UINT bit_offset = BitReadPosition % 8;
- BitReadPosition += num_bits;
- UINT bit_count = 8 - bit_offset;
- if (bit_count>num_bits) bit_count=num_bits;
- value = (ULONG(Buffer[byte_num++]) << (bit_offset+24));
- num_bits-=bit_count;
- for (int shift=24-bit_count;shift>0;shift-=8,num_bits-=8) value|=unsigned(Buffer[byte_num++]) << shift;
- if (num_bits>0) value|=Buffer[byte_num++]>>(-shift);
- value >>= 32-read_len;
- #endif
- }
- //-----------------------------------------------------------------------------
- //
- // This method is only for use by a packet class when data is received.
- //
- void cBitPacker::Set_Bit_Write_Position(UINT position)
- {
- //WWASSERT(position <= BufferSize * 8);
- WWASSERT(position <= MAX_BUFFER_SIZE * 8);
- BitWritePosition = position;
- }
- /*
- //-----------------------------------------------------------------------------
- void cBitPacker::Increment_Bit_Position(int num_bits)
- {
- WWASSERT(num_bits >= 0);
- for (int i = 0; i < num_bits; i++) {
- Advance_Bit_Position();
- NumBits++;
- }
- }
- //-----------------------------------------------------------------------------
- UINT cBitPacker::Get_Compressed_Size_Bytes() const
- {
- return (int) ceil(BitWritePosition / 8.0f);
- }
- //-----------------------------------------------------------------------------
- inline void cBitPacker::Advance_Bit_Position()
- {
- BitWritePosition++;
-
- //
- // If the following assert hits then our buffer is not large enough.
- // We can advance BitWritePosition one bit past the end of the buffer, but
- // we cannot write there.
- //
- //WWASSERT(BitWritePosition < BufferSize * 8);
- WWASSERT(BitWritePosition <= BufferSize * 8);
- }
- */
|