| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /*
- ** 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/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWPhys *
- * *
- * $Archive:: /Commando/Code/wwphys/vistable.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 6/11/01 6:06p $*
- * *
- * $Revision:: 24 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "vistable.h"
- #include "wwphysids.h"
- #include "pscene.h"
- #include "chunkio.h"
- #include "wwdebug.h"
- #include "lzo.h"
- #include "lzo1x.h"
- #include "phys.h"
- #include "wwmemlog.h"
- #include <windows.h>
- /*
- ** Chunk ID's used by a visibility table to save itself
- */
- enum {
- VISTABLE_CHUNK_BYTECOUNT = 0x00000001, // number of bytes in this pvs
- VISTABLE_CHUNK_BYTES, // pvs bytes, compressed with lzhl (OBSOLETE!)
- VISTABLE_CHUNK_LZOBYTES // pvs bytes, compressed with lzo
- };
- /**
- ** BitCounterClass
- ** This class is used to accelerate some of the bit-vector comparing and counting that
- ** goes on in VisTableClass.
- */
- class BitCounterClass
- {
- public:
- BitCounterClass(void);
-
- int Count_True_Bits(uint8 byte) { return TrueBits[byte]; }
- protected:
- uint8 TrueBits[256];
- };
- BitCounterClass::BitCounterClass(void)
- {
- /*
- ** Initialize the table of how many "on" bits there are
- ** in each number between 0 and 256
- */
- for (int i=0; i<256; i++) {
- TrueBits[i] = 0;
- for (int bit=0; bit<8; bit++) {
- if (i & (1<<bit)) {
- TrueBits[i]++;
- }
- }
- }
- }
- static BitCounterClass _TheBitCounter;
- /****************************************************************************************************
- **
- ** VisTableClass Implementation
- **
- ****************************************************************************************************/
- VisTableClass::VisTableClass(unsigned bitcount,int id) :
- BitCount(bitcount),
- Buffer(NULL),
- VisSectorID(id),
- Timestamp(0)
- {
- Alloc_Buffer(bitcount);
- }
- VisTableClass::VisTableClass(CompressedVisTableClass * ctable,int bitcount,int id) :
- BitCount(bitcount),
- Buffer(NULL),
- VisSectorID(id),
- Timestamp(0)
- {
- WWASSERT(ctable != NULL);
- Alloc_Buffer(bitcount);
- ctable->Decompress(Get_Bytes(),Get_Byte_Count());
- }
- VisTableClass::VisTableClass(const VisTableClass & that) :
- BitCount(0),
- Buffer(NULL),
- VisSectorID(0),
- Timestamp(0)
- {
- *this = that;
- }
- VisTableClass & VisTableClass::operator = (const VisTableClass & that)
- {
- Alloc_Buffer(that.BitCount);
- memcpy(Buffer,that.Buffer,Get_Byte_Count());
- BitCount = that.BitCount;
- VisSectorID = that.VisSectorID;
- Timestamp = that.Timestamp;
- return *this;
- }
- VisTableClass::~VisTableClass(void)
- {
- if (Buffer != NULL) {
- delete[] Buffer;
- Buffer = NULL;
- }
- BitCount = 0;
- }
- void VisTableClass::Alloc_Buffer(int bitcount)
- {
- WWMEMLOG(MEM_VIS);
- if (Buffer != NULL) {
- delete[] Buffer;
- Buffer = NULL;
- }
- BitCount = bitcount;
- int count = ((bitcount + 31) / 32);
- Buffer = new uint32[count];
- memset(Buffer,0,count * sizeof(uint32));
- }
- uint8 * VisTableClass::Get_Bytes(void) const
- {
- return (uint8*)Buffer;
- }
- int VisTableClass::Get_Byte_Count(void) const
- {
- /*
- ** In order to avoid "endian-ness" problems in the routines that
- ** loop over the bytes in the buffer, I'm returning the byte count
- ** up to the last longword. The extra bits should always be zero
- ** so they should not screw up anything.
- */
- return Get_Long_Count() * 4; //(BitCount + 7) / 8;
- }
- uint32 * VisTableClass::Get_Longs(void) const
- {
- return Buffer;
- }
- int VisTableClass::Get_Long_Count(void) const
- {
- return (BitCount + 31) / 32;
- }
- void VisTableClass::Reset_All(void)
- {
- if (Buffer != NULL) {
- memset(Buffer,0x00,Get_Byte_Count());
- }
- }
- void VisTableClass::Set_All(void)
- {
- /*
- ** Set the buffer to FF's
- */
- if (Buffer != NULL) {
- memset((uint8*)Buffer,0xFF,Get_Byte_Count());
- }
-
- /*
- ** Make sure the trailing bits are zero'd (just for sanity...)
- */
- for (int i=BitCount; i<32*Get_Long_Count(); i++) {
- Buffer[i>>5] &= ~(0x80000000u >> (i & 0x01F));
- }
- }
- void VisTableClass::Delete_Bit(int delete_index)
- {
- int i;
- /*
- ** first handle the long that the deleted bit is in
- */
- int first_long = delete_index >> 5;
- int start_bits = WWMath::Min((first_long + 1)<<5,BitCount-1);
-
- for (i=delete_index; i<start_bits; i++) {
- Set_Bit(i,(Get_Bit(i+1) != 0));
- }
-
- /*
- ** handle the reset of the buffer. There are two cases here, if the deleted
- ** bit was in the last long of the buffer, we simply have to clear the trailing
- ** bit. Otherwise we need to shift the rest of the longs in the buffer right
- ** by one bit and or in the MSB from the following long.
- */
- int long_count = Get_Long_Count();
- if (first_long == long_count-1) {
- Set_Bit(BitCount-1,false);
- } else {
- for (i=first_long+1; i<long_count-1; i++) {
- Buffer[i] = (Buffer[i]<<1) | ((Buffer[i+1] & 0x80000000) >> 31);
- }
- Buffer[long_count-1] = Buffer[long_count-1]<<1;
- }
-
- /*
- ** Finally, record that a bit was removed.
- */
- BitCount--;
- }
- void VisTableClass::Merge(const VisTableClass & that)
- {
- if (that.BitCount != BitCount) {
- return;
- }
- for (int i=0; i<Get_Long_Count(); i++) {
- Buffer[i] = Buffer[i] | that.Buffer[i];
- }
- }
- void VisTableClass::Invert(void)
- {
- for (int i=0; i<Get_Long_Count(); i++) {
- Buffer[i] = ~Buffer[i];
- }
- }
- bool VisTableClass::Is_Equal_To(const VisTableClass & that)
- {
- if (BitCount != that.BitCount) {
- return false;
- }
- if (memcmp((void*)Buffer,(void*)that.Buffer,Get_Byte_Count()) != 0) {
- return false;
- }
- return true;
- }
- int VisTableClass::Count_Differences(const VisTableClass & that)
- {
- if (BitCount != that.BitCount) {
- return BitCount;
- }
- int counter = 0;
- int byte_count = Get_Byte_Count();
- uint8 * my_bytes = Get_Bytes();
- uint8 * his_bytes = that.Get_Bytes();
- for (int i=0; i<byte_count; i++) {
- counter += _TheBitCounter.Count_True_Bits(my_bytes[i] ^ his_bytes[i]);
- }
- return counter;
- }
- int VisTableClass::Count_True_Bits(void)
- {
- int counter = 0;
- int byte_count = Get_Byte_Count();
- uint8 * my_bytes = Get_Bytes();
- for (int i=0; i<byte_count; i++) {
- counter += _TheBitCounter.Count_True_Bits(my_bytes[i]);
- }
- return counter;
- }
- float VisTableClass::Match_Fraction(const VisTableClass & that)
- {
- if (BitCount != that.BitCount) {
- return 0.0f;
- }
-
- /*
- ** or_counter will be the number of bits that were on in at least one of the vectors
- ** xor_counter will be the count of bits that were different (1 in one and zero in the other)
- */
- int xor_counter = 0;
- int or_counter = 0;
- int byte_count = Get_Byte_Count();
- uint8 * my_bytes = Get_Bytes();
- uint8 * his_bytes = that.Get_Bytes();
- for (int i=0; i<byte_count; i++) {
- xor_counter += _TheBitCounter.Count_True_Bits(my_bytes[i] ^ his_bytes[i]);
- or_counter += _TheBitCounter.Count_True_Bits(my_bytes[i] | his_bytes[i]);
- }
- /*
- ** match fraction is 1 - (different_bits / on_bits)
- */
- if (or_counter == 0) {
- return 1.0f;
- } else {
- return 1.0f - (float)xor_counter / (float)or_counter;
- }
- }
- /****************************************************************************************************
- **
- ** CompressedVisTableClass Implementation
- **
- ****************************************************************************************************/
- CompressedVisTableClass::CompressedVisTableClass(void) :
- BufferSize(0),
- Buffer(NULL)
- {
- }
- CompressedVisTableClass::CompressedVisTableClass(VisTableClass * bits) :
- BufferSize(0),
- Buffer(NULL)
- {
- WWMEMLOG(MEM_VIS);
- WWASSERT(bits != NULL);
- Compress(bits->Get_Bytes(),bits->Get_Byte_Count());
- }
- CompressedVisTableClass::CompressedVisTableClass(const CompressedVisTableClass &that) :
- BufferSize(0),
- Buffer(NULL)
- {
- (*this) = that;
- }
- CompressedVisTableClass::~CompressedVisTableClass(void)
- {
- if (Buffer != NULL) {
- delete[] Buffer;
- }
- }
- const CompressedVisTableClass &CompressedVisTableClass::operator= (const CompressedVisTableClass &that)
- {
- WWMEMLOG(MEM_VIS);
- if (Buffer != NULL) {
- delete [] Buffer;
- Buffer = NULL;
- }
- BufferSize = that.BufferSize;
- Buffer = new uint8[BufferSize];
- ::memcpy (Buffer, that.Buffer, sizeof(uint8)*BufferSize);
- return *this;
- }
- uint8 * CompressedVisTableClass::Get_Bytes(void)
- {
- return Buffer;
- }
- int CompressedVisTableClass::Get_Byte_Count(void) const
- {
- return BufferSize;
- }
- void CompressedVisTableClass::Load(ChunkLoadClass & cload)
- {
- WWMEMLOG(MEM_VIS);
- VisTableClass * old_table = NULL;
- if (Buffer != NULL) {
- old_table = NEW_REF(VisTableClass,(this,PhysicsSceneClass::Get_Instance()->Get_Vis_Table_Size(),0));
- delete[] Buffer;
- }
-
- cload.Open_Chunk();
- if (cload.Cur_Chunk_ID() != VISTABLE_CHUNK_BYTECOUNT) {
- cload.Close_Chunk();
- return;
- }
- cload.Read(&BufferSize,sizeof(BufferSize));
- cload.Close_Chunk();
- Buffer = new uint8[BufferSize];
-
- /*
- ** Load the compressed visibility bits. At one point in the past,
- ** we were using the lzhl compression scheme, if we encounter that chunk,
- ** just reset vis because that compressor had bugs and the data is probably
- ** invalid
- */
- bool load_error = false;
- while (cload.Open_Chunk()) {
- switch (cload.Cur_Chunk_ID()) {
- case VISTABLE_CHUNK_BYTES:
- cload.Read(Buffer,BufferSize);
- PhysicsSceneClass::Get_Instance()->Reset_Vis();
- load_error = true;
- break;
- case VISTABLE_CHUNK_LZOBYTES:
- WWASSERT(cload.Cur_Chunk_Length() == (uint32)BufferSize);
- cload.Read(Buffer,BufferSize);
- break;
- default:
- WWDEBUG_SAY(("Unhandled chunk ID: %d in vistable.cpp\r\n",cload.Cur_Chunk_ID()));
- load_error = true;
- break;
- }
- cload.Close_Chunk();
- }
- /*
- ** if we loaded a valid vis table and we had a previous valid table, merge
- ** the two together
- */
- if ((load_error == false) && (old_table != NULL)) {
- VisTableClass * new_table = NEW_REF(VisTableClass,(this,PhysicsSceneClass::Get_Instance()->Get_Vis_Table_Size(),0));
- new_table->Merge(*old_table);
- Compress(new_table->Get_Bytes(),new_table->Get_Byte_Count());
- REF_PTR_RELEASE(new_table);
- }
- REF_PTR_RELEASE(old_table);
- }
- void CompressedVisTableClass::Save(ChunkSaveClass & csave)
- {
- uint32 bytecount = BufferSize;
- csave.Begin_Chunk(VISTABLE_CHUNK_BYTECOUNT);
- csave.Write(&bytecount,sizeof(bytecount));
- csave.End_Chunk();
- csave.Begin_Chunk(VISTABLE_CHUNK_LZOBYTES);
- csave.Write(Buffer,bytecount);
- csave.End_Chunk();
- }
- void CompressedVisTableClass::Load (void* hfile)
- {
- WWMEMLOG(MEM_VIS);
- /*
- ** Free the buffer
- */
- if (Buffer != NULL) {
- delete [] Buffer;
- Buffer = NULL;
- BufferSize = 0L;
- }
- if ((HANDLE)hfile != INVALID_HANDLE_VALUE) {
- /*
- ** Read the buffer size
- */
- uint32 dwbytes_read = 0L;
- ::ReadFile ((HANDLE)hfile, &BufferSize, sizeof (BufferSize), &dwbytes_read, NULL);
- /*
- ** Read the buffer
- */
- Buffer = new uint8[BufferSize];
- ::ReadFile ((HANDLE)hfile, Buffer, sizeof (uint8) * BufferSize, &dwbytes_read, NULL);
- }
-
- return;
- }
- void CompressedVisTableClass::Save (void* hfile)
- {
- if ((HANDLE)hfile != INVALID_HANDLE_VALUE) {
- /*
- ** Write the buffer size
- */
- uint32 dwbytes_written = 0L;
- ::WriteFile ((HANDLE)hfile, &BufferSize, sizeof (BufferSize), &dwbytes_written, NULL);
- /*
- ** Write the buffer
- */
- ::WriteFile ((HANDLE)hfile, Buffer, sizeof (uint8) * BufferSize, &dwbytes_written, NULL);
- }
-
- return;
- }
- void CompressedVisTableClass::Compress(uint8 * src_buffer,int src_size)
- {
- WWMEMLOG(MEM_VIS);
- if (Buffer != NULL) {
- delete[] Buffer;
- Buffer = NULL;
- }
-
- uint8 * comp_buffer = new uint8[LZO_BUFFER_SIZE(src_size)];
- lzo_uint comp_size;
- int lzocode = LZOCompressor::Compress(src_buffer,src_size,comp_buffer,&comp_size);
- WWASSERT(lzocode == LZO_E_OK);
- BufferSize = comp_size;
- Buffer = new uint8[BufferSize];
- memcpy(Buffer,comp_buffer,BufferSize);
- #ifdef WWDEBUG
- lzo_uint decomp_size;
- LZOCompressor::Decompress(Buffer,BufferSize,comp_buffer,&decomp_size);
- WWASSERT(decomp_size == (lzo_uint)src_size);
- WWASSERT(src_size % 4 == 0);
- #endif
- delete[] comp_buffer;
- }
- void CompressedVisTableClass::Decompress(uint8 * decomp_buffer,int decomp_size)
- {
- WWMEMLOG(MEM_VIS);
- lzo_uint size;
- LZOCompressor::Decompress(Buffer,BufferSize,decomp_buffer, &size);
- WWASSERT((int)size == decomp_size);
- }
- #if 0
- void CompressedVisTableClass::Compare_Compression(void)
- {
- #ifdef WWDEBUG
- static int num_compressions = 0;
- static int total_size = 0;
- static int lcw_size = 0;
- static int lzo_size = 0;
- static int lcw_failures = 0;
- static int lzo_failures = 0;
- int test_size = tmp_size;
- uint8 * test_buf = tmp_buffer;
- num_compressions++;
- total_size += test_size;
-
- // Testing LCW
- uint8 * lcw_comp_buf = new uint8[test_size * 2];
- int lcw_comp_size = LCW_Comp(test_buf, lcw_comp_buf, test_size);
- uint8 * lcw_decomp_buf = new uint8[test_size * 2];
- int lcw_decomp_size = LCW_Uncomp(lcw_comp_buf, lcw_decomp_buf);
- lcw_size+=lcw_comp_size;
- if ((memcmp(test_buf,lcw_decomp_buf,test_size) != 0) || (lcw_decomp_size != test_size)) {
- lcw_failures++;
- }
-
- // Testing LZO
- uint8 * lzo_comp_buf = new uint8[test_size * 2]; //LZO_BUFFER_SIZE(test_size)];
- lzo_uint lzo_comp_size;
- LZOCompressor::Compress(test_buf,test_size,lzo_comp_buf,&lzo_comp_size);
- uint8 * lzo_decomp_buf = new uint8[test_size];
- lzo_uint lzo_decomp_size;
- LZOCompressor::Decompress(lzo_comp_buf,lzo_comp_size,lzo_decomp_buf,&lzo_decomp_size);
- lzo_size+=lzo_comp_size;
- if ((memcmp(test_buf,lzo_decomp_buf,test_size) != 0) || ((int)lzo_decomp_size != test_size)) {
- lzo_failures++;
- }
- delete[] lcw_comp_buf;
- delete[] lcw_decomp_buf;
- delete[] lzo_comp_buf;
- delete[] lzo_decomp_buf;
- #endif
- delete[] tmp_buffer;
- }
- #endif
|