bchannel.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : W3D Tools *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/max2w3d/bchannel.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 10/30/00 5:25p $*
  29. * *
  30. * $Revision:: 6 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "bchannel.h"
  36. #include "w3d_file.h"
  37. #include "logdlg.h"
  38. #include "exportlog.h"
  39. BitChannelClass::BitChannelClass
  40. (
  41. uint32 id,
  42. int maxframes,
  43. uint32 chntype,
  44. bool default_val
  45. ) :
  46. ID(id),
  47. ChannelType(chntype),
  48. MaxFrames(maxframes),
  49. IsEmpty(true),
  50. DefaultVal(default_val),
  51. Data(maxframes),
  52. Begin(0),
  53. End(0)
  54. {
  55. // start "Begin" at the end of the array, whenever we set a value
  56. // at an index less than "Begin", we push "Begin" back.
  57. Begin = MaxFrames;
  58. End = 0;
  59. }
  60. BitChannelClass::~BitChannelClass(void)
  61. {
  62. }
  63. void BitChannelClass::Set_Bit(int frameidx,bool bit)
  64. {
  65. assert(frameidx >= 0);
  66. assert(frameidx < MaxFrames);
  67. Data[frameidx] = bit;
  68. if (!is_default(bit)) {
  69. IsEmpty = false;
  70. }
  71. }
  72. void BitChannelClass::Set_Bits(BooleanVectorClass & bits)
  73. {
  74. for (int i=0; i<bits.Length(); i++) {
  75. Set_Bit(i,bits[i]);
  76. }
  77. }
  78. bool BitChannelClass::Get_Bit(int frameidx)
  79. {
  80. assert(frameidx >= 0);
  81. assert(frameidx < MaxFrames);
  82. return Data[frameidx];
  83. }
  84. bool BitChannelClass::Save(ChunkSaveClass & csave, bool compress)
  85. {
  86. if (IsEmpty) return true;
  87. if (compress) {
  88. // Save the Channel Data Compressed
  89. // TIMECODED
  90. if (!csave.Begin_Chunk(W3D_CHUNK_COMPRESSED_BIT_CHANNEL)) {
  91. return false;
  92. }
  93. uint32 channelsize = sizeof(W3dTimeCodedBitChannelStruct);
  94. uint32 packetsize = sizeof(uint32);
  95. channelsize += packetsize * MaxFrames;
  96. channelsize -= sizeof(uint32);
  97. W3dTimeCodedBitChannelStruct * chn = (W3dTimeCodedBitChannelStruct *)malloc(channelsize);
  98. if (chn == NULL) {
  99. return false;
  100. }
  101. chn->NumTimeCodes = MaxFrames;
  102. chn->Pivot = ID;
  103. chn->Flags = ChannelType;
  104. chn->DefaultVal = DefaultVal;
  105. // copy data into the channel struct, in timecoded raw format
  106. for (uint32 fcount=0; fcount < chn->NumTimeCodes; fcount++) {
  107. if (Get_Bit(fcount)) {
  108. chn->Data[fcount] = fcount | W3D_TIMECODED_BIT_MASK;
  109. }
  110. else {
  111. chn->Data[fcount] = fcount;
  112. }
  113. }
  114. // Compress the new structure
  115. BitChannelClass::compress( chn );
  116. float originalchannelsize = channelsize;
  117. // Update Channel Size
  118. channelsize = sizeof(W3dTimeCodedBitChannelStruct);
  119. channelsize += packetsize * chn->NumTimeCodes;
  120. channelsize -= sizeof(uint32);
  121. float percent = (((float) channelsize) / originalchannelsize) * 100.0f;
  122. ExportLog::printf("%.0f", percent);
  123. // save
  124. if (csave.Write(chn,channelsize) != channelsize) {
  125. return false;
  126. }
  127. if (chn != NULL) {
  128. free(chn);
  129. }
  130. if (!csave.End_Chunk()) {
  131. return false;
  132. }
  133. }
  134. else {
  135. // Stock Raw Save
  136. if (!csave.Begin_Chunk(W3D_CHUNK_BIT_CHANNEL)) {
  137. return false;
  138. }
  139. compute_range();
  140. int numbits = End - Begin + 1;
  141. assert(numbits > 0);
  142. int numbytes = (numbits + 7) / 8;
  143. unsigned int channelsize = sizeof(W3dBitChannelStruct);
  144. channelsize += numbytes - 1; // one byte inside the W3dBitChannelStruct...
  145. W3dBitChannelStruct * chn = (W3dBitChannelStruct *)malloc(channelsize);
  146. if (chn == NULL) {
  147. return false;
  148. }
  149. chn->FirstFrame = Begin;
  150. chn->LastFrame = End;
  151. chn->Flags = ChannelType;
  152. chn->Pivot = ID;
  153. chn->DefaultVal = DefaultVal;
  154. uint8 * bits = (uint8 *)&(chn->Data[0]);
  155. for (int fcount=0; fcount < End-Begin+1; fcount++) {
  156. ::Set_Bit(bits,fcount,Get_Bit(Begin + fcount));
  157. }
  158. if (csave.Write(chn,channelsize) != channelsize) {
  159. return false;
  160. }
  161. if (chn != NULL) {
  162. free(chn);
  163. }
  164. if (!csave.End_Chunk()) {
  165. return false;
  166. }
  167. }
  168. return true;
  169. }
  170. bool BitChannelClass::is_default(bool bit)
  171. {
  172. return (bit == DefaultVal);
  173. }
  174. void BitChannelClass::compute_range(void)
  175. {
  176. Begin = 0;
  177. while ((Begin < MaxFrames) && (is_default(Get_Bit(Begin)))) {
  178. Begin++;
  179. }
  180. End = MaxFrames-1;
  181. while ((End >= 0) && (is_default(Get_Bit(End)))) {
  182. End--;
  183. }
  184. } // compute_range
  185. //
  186. // find a packet that isn't needed, and return the index
  187. // if all packets are necessary, then return back PACKETS_ALL_USEFUL
  188. // a useless packet is defined, as a packet that can be recreated
  189. //
  190. #define PACKETS_ALL_USEFUL (0xFFFFFFFF)
  191. //
  192. uint32 BitChannelClass::find_useless_packet(W3dTimeCodedBitChannelStruct * c)
  193. {
  194. assert( c ); // make sure pointer exists
  195. assert( c->NumTimeCodes ); // make sure some packets exist
  196. if (c->NumTimeCodes > 2) {
  197. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 1); try_idx++) {
  198. if ((c->Data[try_idx] & W3D_TIMECODED_BIT_MASK) ==
  199. (c->Data[try_idx+1] & W3D_TIMECODED_BIT_MASK)) {
  200. return(try_idx + 1);
  201. }
  202. } // for
  203. }
  204. return( PACKETS_ALL_USEFUL );
  205. } // find_useless_packet
  206. //
  207. // Remove a packet from a W3dTimeCodedBitChannelStruct
  208. //
  209. void BitChannelClass::remove_packet(W3dTimeCodedBitChannelStruct * c, uint32 packet_idx)
  210. {
  211. assert( c );
  212. assert( c->NumTimeCodes > 1 );
  213. uint32 packet_size = 1;
  214. uint32 packet_len = packet_size * sizeof(uint32);
  215. uint32 *src, *dst;
  216. dst = (uint32 *) &c->Data[ packet_size * packet_idx ];
  217. src = (uint32 *) &c->Data[ packet_size * (packet_idx + 1) ];
  218. uint32 copy_length = (c->NumTimeCodes - (packet_idx + 1)) * packet_len;
  219. if (copy_length) {
  220. memcpy(dst, src, copy_length);
  221. }
  222. // Decrement Packet Count
  223. c->NumTimeCodes--;
  224. } // remove_packet
  225. //
  226. // Take a non-compressed TimeCoded Bit Channel
  227. // and compress the packets
  228. //
  229. void BitChannelClass::compress(W3dTimeCodedBitChannelStruct * c)
  230. {
  231. while(1) {
  232. uint32 idx = find_useless_packet( c );
  233. if (PACKETS_ALL_USEFUL == idx) break;
  234. remove_packet( c, idx );
  235. }
  236. } // compress
  237. // EOF - bchannel.cpp