/* ** Command & Conquer Generals Zero Hour(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 . */ /*********************************************************************************************** *** 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 : W3D Tools * * * * $Archive:: /Commando/Code/Tools/max2w3d/bchannel.cpp $* * * * $Author:: Greg_h $* * * * $Modtime:: 10/30/00 5:25p $* * * * $Revision:: 6 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "bchannel.h" #include "w3d_file.h" #include "logdlg.h" #include "exportlog.h" BitChannelClass::BitChannelClass ( uint32 id, int maxframes, uint32 chntype, bool default_val ) : ID(id), ChannelType(chntype), MaxFrames(maxframes), IsEmpty(true), DefaultVal(default_val), Data(maxframes), Begin(0), End(0) { // start "Begin" at the end of the array, whenever we set a value // at an index less than "Begin", we push "Begin" back. Begin = MaxFrames; End = 0; } BitChannelClass::~BitChannelClass(void) { } void BitChannelClass::Set_Bit(int frameidx,bool bit) { assert(frameidx >= 0); assert(frameidx < MaxFrames); Data[frameidx] = bit; if (!is_default(bit)) { IsEmpty = false; } } void BitChannelClass::Set_Bits(BooleanVectorClass & bits) { for (int i=0; i= 0); assert(frameidx < MaxFrames); return Data[frameidx]; } bool BitChannelClass::Save(ChunkSaveClass & csave, bool compress) { if (IsEmpty) return true; if (compress) { // Save the Channel Data Compressed // TIMECODED if (!csave.Begin_Chunk(W3D_CHUNK_COMPRESSED_BIT_CHANNEL)) { return false; } uint32 channelsize = sizeof(W3dTimeCodedBitChannelStruct); uint32 packetsize = sizeof(uint32); channelsize += packetsize * MaxFrames; channelsize -= sizeof(uint32); W3dTimeCodedBitChannelStruct * chn = (W3dTimeCodedBitChannelStruct *)malloc(channelsize); if (chn == NULL) { return false; } chn->NumTimeCodes = MaxFrames; chn->Pivot = ID; chn->Flags = ChannelType; chn->DefaultVal = DefaultVal; // copy data into the channel struct, in timecoded raw format for (uint32 fcount=0; fcount < chn->NumTimeCodes; fcount++) { if (Get_Bit(fcount)) { chn->Data[fcount] = fcount | W3D_TIMECODED_BIT_MASK; } else { chn->Data[fcount] = fcount; } } // Compress the new structure BitChannelClass::compress( chn ); float originalchannelsize = channelsize; // Update Channel Size channelsize = sizeof(W3dTimeCodedBitChannelStruct); channelsize += packetsize * chn->NumTimeCodes; channelsize -= sizeof(uint32); float percent = (((float) channelsize) / originalchannelsize) * 100.0f; ExportLog::printf("%.0f", percent); // save if (csave.Write(chn,channelsize) != channelsize) { return false; } if (chn != NULL) { free(chn); } if (!csave.End_Chunk()) { return false; } } else { // Stock Raw Save if (!csave.Begin_Chunk(W3D_CHUNK_BIT_CHANNEL)) { return false; } compute_range(); int numbits = End - Begin + 1; assert(numbits > 0); int numbytes = (numbits + 7) / 8; unsigned int channelsize = sizeof(W3dBitChannelStruct); channelsize += numbytes - 1; // one byte inside the W3dBitChannelStruct... W3dBitChannelStruct * chn = (W3dBitChannelStruct *)malloc(channelsize); if (chn == NULL) { return false; } chn->FirstFrame = Begin; chn->LastFrame = End; chn->Flags = ChannelType; chn->Pivot = ID; chn->DefaultVal = DefaultVal; uint8 * bits = (uint8 *)&(chn->Data[0]); for (int fcount=0; fcount < End-Begin+1; fcount++) { ::Set_Bit(bits,fcount,Get_Bit(Begin + fcount)); } if (csave.Write(chn,channelsize) != channelsize) { return false; } if (chn != NULL) { free(chn); } if (!csave.End_Chunk()) { return false; } } return true; } bool BitChannelClass::is_default(bool bit) { return (bit == DefaultVal); } void BitChannelClass::compute_range(void) { Begin = 0; while ((Begin < MaxFrames) && (is_default(Get_Bit(Begin)))) { Begin++; } End = MaxFrames-1; while ((End >= 0) && (is_default(Get_Bit(End)))) { End--; } } // compute_range // // find a packet that isn't needed, and return the index // if all packets are necessary, then return back PACKETS_ALL_USEFUL // a useless packet is defined, as a packet that can be recreated // #define PACKETS_ALL_USEFUL (0xFFFFFFFF) // uint32 BitChannelClass::find_useless_packet(W3dTimeCodedBitChannelStruct * c) { assert( c ); // make sure pointer exists assert( c->NumTimeCodes ); // make sure some packets exist if (c->NumTimeCodes > 2) { for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 1); try_idx++) { if ((c->Data[try_idx] & W3D_TIMECODED_BIT_MASK) == (c->Data[try_idx+1] & W3D_TIMECODED_BIT_MASK)) { return(try_idx + 1); } } // for } return( PACKETS_ALL_USEFUL ); } // find_useless_packet // // Remove a packet from a W3dTimeCodedBitChannelStruct // void BitChannelClass::remove_packet(W3dTimeCodedBitChannelStruct * c, uint32 packet_idx) { assert( c ); assert( c->NumTimeCodes > 1 ); uint32 packet_size = 1; uint32 packet_len = packet_size * sizeof(uint32); uint32 *src, *dst; dst = (uint32 *) &c->Data[ packet_size * packet_idx ]; src = (uint32 *) &c->Data[ packet_size * (packet_idx + 1) ]; uint32 copy_length = (c->NumTimeCodes - (packet_idx + 1)) * packet_len; if (copy_length) { memcpy(dst, src, copy_length); } // Decrement Packet Count c->NumTimeCodes--; } // remove_packet // // Take a non-compressed TimeCoded Bit Channel // and compress the packets // void BitChannelClass::compress(W3dTimeCodedBitChannelStruct * c) { while(1) { uint32 idx = find_useless_packet( c ); if (PACKETS_ALL_USEFUL == idx) break; remove_packet( c, idx ); } } // compress // EOF - bchannel.cpp