vchannel.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  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. /* $Header: /Commando/Code/Tools/max2w3d/vchannel.cpp 10 10/30/00 6:56p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando Tools - W3D export *
  24. * *
  25. * $Archive:: /Commando/Code/Tools/max2w3d/vchannel.cpp $*
  26. * *
  27. * $Author:: Greg_h $*
  28. * *
  29. * $Modtime:: 10/30/00 5:26p $*
  30. * *
  31. * $Revision:: 10 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #include "vchannel.h"
  37. #include <assert.h>
  38. #include <string.h>
  39. #include <stdlib.h>
  40. #include "w3d_file.h"
  41. #include "w3dquat.h"
  42. #include "bchannel.h"
  43. #include "exportlog.h"
  44. #define FILTER_TABLE_SIZE (256)
  45. #define FILTER_TABLE_GEN_START (16)
  46. #define FILTER_TABLE_GEN_SIZE (FILTER_TABLE_SIZE - FILTER_TABLE_GEN_START)
  47. static float filtertable[FILTER_TABLE_SIZE] = {
  48. 0.00000001f,
  49. 0.0000001f,
  50. 0.000001f,
  51. 0.00001f,
  52. 0.0001f,
  53. 0.001f,
  54. 0.01f,
  55. 0.1f,
  56. 1.0f,
  57. 10.0f,
  58. 100.0f,
  59. 1000.0f,
  60. 10000.0f,
  61. 100000.0f,
  62. 1000000.0f,
  63. 10000000.0f,
  64. };
  65. static bool table_valid = false;
  66. VectorChannelClass::VectorChannelClass
  67. (
  68. uint32 id,
  69. int maxframes,
  70. uint32 flags,
  71. int vectorlength,
  72. float32 * identvect
  73. ) :
  74. ID(id),
  75. Flags(flags),
  76. MaxFrames(maxframes),
  77. VectorLen(vectorlength),
  78. IsEmpty(true),
  79. IdentVect(NULL),
  80. Data(NULL),
  81. Begin(0),
  82. End(0),
  83. ReduceAnimation(false),
  84. ReduceAnimationPercent(0),
  85. CompressAnimation(false),
  86. CompressAnimationFlavor(0),
  87. CompressAnimationTranslationError(0.0f),
  88. CompressAnimationRotationError(0.0f)
  89. {
  90. assert(VectorLen > 0);
  91. IdentVect = new float32[VectorLen];
  92. Data = new float32[MaxFrames * VectorLen];
  93. assert(Data);
  94. assert(IdentVect);
  95. memcpy(IdentVect,identvect,VectorLen * sizeof(float32));
  96. memset(Data,0,MaxFrames * VectorLen * sizeof(float32));
  97. // start "Begin" at the end of the array, whenever we set a value
  98. // at an index less than "Begin", we push "Begin" back.
  99. Begin = MaxFrames;
  100. End = 0;
  101. if (false == table_valid) {
  102. // Create Filter Table, used in delta compression
  103. for (int i=0; i<FILTER_TABLE_GEN_SIZE; i++)
  104. {
  105. float ratio = i;
  106. //ratio = ((ratio + 1.0f) / 128.0f);
  107. ratio/=((float) FILTER_TABLE_GEN_SIZE);
  108. filtertable[i + FILTER_TABLE_GEN_START] = 1.0f - sin( DEG_TO_RAD(90.0f * ratio));
  109. }
  110. table_valid = true;
  111. }
  112. }
  113. VectorChannelClass::~VectorChannelClass(void)
  114. {
  115. if (Data) {
  116. delete[] Data;
  117. }
  118. if (IdentVect) {
  119. delete[] IdentVect;
  120. }
  121. }
  122. void VectorChannelClass::Set_Vector(int frameidx,float32 * vector)
  123. {
  124. assert(frameidx >= 0);
  125. assert(frameidx < MaxFrames);
  126. for (int vi=0; vi<VectorLen; vi++) {
  127. set_value(frameidx,vi,vector[vi]);
  128. }
  129. if (!is_identity(vector)) {
  130. IsEmpty = false;
  131. }
  132. }
  133. float * VectorChannelClass::Get_Vector(int frameidx)
  134. {
  135. assert(frameidx >= 0);
  136. assert(frameidx < MaxFrames);
  137. return &(Data[frameidx * VectorLen]);
  138. }
  139. bool VectorChannelClass::SaveTimeCoded(ChunkSaveClass & csave, BitChannelClass *binmov)
  140. {
  141. uint32 channelsize = sizeof(W3dTimeCodedAnimChannelStruct);
  142. uint32 packetsize = (VectorLen * sizeof(float32)) + sizeof(uint32);
  143. channelsize += packetsize * MaxFrames;
  144. channelsize -= sizeof(uint32);
  145. W3dTimeCodedAnimChannelStruct * chn = (W3dTimeCodedAnimChannelStruct *)malloc(channelsize);
  146. if (chn == NULL) {
  147. return false;
  148. }
  149. chn->NumTimeCodes = MaxFrames;
  150. chn->VectorLen = VectorLen;
  151. chn->Pivot = ID;
  152. chn->Flags = Flags;
  153. // Fetch Channel Data into new format
  154. // tc [data] tc [data] tc [data] .. ...
  155. uint32 fidx = 0;
  156. for (int fcount=0; fcount < MaxFrames; fcount++, fidx += (VectorLen+1) ) {
  157. uint32 * pivec;
  158. float32 * pfvec;
  159. pivec = &chn->Data[ fidx ];
  160. pfvec = (float32 *) (pivec + 1);
  161. *pivec = fcount;
  162. if (binmov) {
  163. bool binary_move = binmov->Get_Bit( fcount );
  164. // check for false binary movement
  165. if (fcount != Begin) {
  166. if (binary_move) {
  167. *pivec |= W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
  168. }
  169. }
  170. else {
  171. //if (log) log->printf("\nFALSE Binary\n");
  172. }
  173. }
  174. // Copy Vector
  175. for (int vidx=0; vidx < VectorLen; vidx++) {
  176. pfvec[vidx] = get_value(fcount,vidx);
  177. }
  178. }
  179. // Compress the new structure
  180. VectorChannelClass::compress( chn );
  181. // update the size
  182. float original_channelsize = channelsize;
  183. channelsize = sizeof(W3dTimeCodedAnimChannelStruct);
  184. channelsize += packetsize * chn->NumTimeCodes;
  185. channelsize -= sizeof(uint32);
  186. float percent = (((float)channelsize) / original_channelsize) * 100.0f;
  187. // save
  188. ExportLog::printf("%.0f", percent);
  189. if (csave.Write(chn,channelsize) != channelsize) {
  190. return false;
  191. }
  192. if (chn != NULL) {
  193. free(chn);
  194. }
  195. if (!csave.End_Chunk()) {
  196. return false;
  197. }
  198. return true;
  199. } // SaveTimeCoded
  200. /*
  201. struct W3dAdaptiveDeltaAnimChannelStruct
  202. {
  203. uint32 NumFrames; // number of frames of animation
  204. uint16 Pivot; // pivot effected by this channel
  205. uint8 VectorLen; // num Channels
  206. uint8 Flags; // channel type
  207. float Scale; // Filter Table Scale
  208. uint32 Data[1]; // OpCode Data Stream
  209. };
  210. */
  211. struct
  212. {
  213. unsigned char filter : 7;
  214. unsigned char flag : 1;
  215. unsigned char d0 : 4;
  216. unsigned char d1 : 4;
  217. unsigned char d2 : 4;
  218. unsigned char d3 : 4;
  219. unsigned char d4 : 4;
  220. unsigned char d5 : 4;
  221. unsigned char d6 : 4;
  222. unsigned char d7 : 4;
  223. unsigned char d8 : 4;
  224. unsigned char d9 : 4;
  225. unsigned char d10 : 4;
  226. unsigned char d11 : 4;
  227. unsigned char d12 : 4;
  228. unsigned char d13 : 4;
  229. unsigned char d14 : 4;
  230. unsigned char d15 : 4;
  231. } AdaptiveDeltaPacketStruct;
  232. //
  233. // test compress Adaptive Delta packet
  234. //
  235. // inputs: filter - forced filter to use
  236. // scale (filter table scale)
  237. // value1 (continue compression from this initial value)
  238. // float *indata // 16 values to compress
  239. // float *outdata // 16 decompressed values
  240. //
  241. // output: float error; // aggregate error for packet
  242. //
  243. float VectorChannelClass::test_compress(int filter_index, float scale, float value1, float *indata, float *outdata)
  244. {
  245. float error = 0.0f;
  246. // compute filter
  247. float filter = filtertable[filter_index] * scale;
  248. assert(filter_index < FILTER_TABLE_SIZE);
  249. float last_value = value1;
  250. for(int data_idx=0; data_idx < 16; data_idx++) {
  251. // NOTE: DETERMINE best factor via Brute Force
  252. // This helps under/over-flow problems
  253. // brute
  254. int best_factor = 100;
  255. float least_error = 999999999.9f;
  256. for (float try_factor = -8.0f; try_factor < 8.0f; try_factor+=1.0f) {
  257. float temp = (try_factor * filter) + last_value; // decompress using this filter
  258. temp-=indata[data_idx]; // delta decompressed value, vs original value
  259. temp=fabs(temp);
  260. if (temp < least_error) {
  261. least_error = temp;
  262. best_factor = try_factor;
  263. }
  264. }
  265. assert(best_factor <= 7);
  266. assert(best_factor >=-8);
  267. float dfactor = best_factor;
  268. outdata[data_idx] = (dfactor * filter) + last_value;
  269. // END BRUTE FORCE IT
  270. float delta = outdata[data_idx] - indata[data_idx];
  271. //if (delta > error) error = delta;
  272. error+= (delta * delta);
  273. last_value = outdata[data_idx];
  274. }
  275. return( sqrt(error) );
  276. } // test_compress
  277. //
  278. // compress Adaptive Delta packet
  279. //
  280. // inputs: filter - forced filter to use
  281. // scale (filter table scale)
  282. // value1 (continue compression from this initial value)
  283. // float *indata // 16 values to compress
  284. // unsigned char *pPacket
  285. //
  286. // output: float error; // aggregate error for packet
  287. //
  288. float VectorChannelClass::compress(int filter_index, float scale, float value1, float *indata, unsigned char *pPacket, float *outdata)
  289. {
  290. float error = 0.0f;
  291. // compute filter
  292. float filter = filtertable[filter_index] * scale;
  293. assert(filter_index < FILTER_TABLE_SIZE);
  294. *pPacket = filter_index;
  295. pPacket++;
  296. float last_value = value1;
  297. for(int data_idx=0; data_idx < 16; data_idx++) {
  298. // NOTE: PLAN TO ADD A LOOP IN HERE, to DETERMINE best factor via Brute Force
  299. // This could help under/over-flow problems
  300. {
  301. // brute
  302. int best_factor = 100;
  303. float least_error = 999999999.9f;
  304. for (float try_factor = -8.0f; try_factor < 8.0f; try_factor+=1.0f) {
  305. float temp = (try_factor * filter) + last_value; // decompress using this filter
  306. temp-=indata[data_idx]; // delta decompressed value, vs original value
  307. temp=fabs(temp);
  308. if (temp < least_error) {
  309. least_error = temp;
  310. best_factor = try_factor;
  311. }
  312. }
  313. assert(best_factor <= 7);
  314. assert(best_factor >=-8);
  315. float dfactor = best_factor;
  316. outdata[data_idx] = (dfactor * filter) + last_value;
  317. int pi = data_idx>>1;
  318. if (data_idx & 1) {
  319. best_factor<<=4;
  320. pPacket[pi]&=0x0f;
  321. pPacket[pi]|=best_factor;
  322. }
  323. else {
  324. best_factor&=0xf;
  325. pPacket[pi]&=0xf0;
  326. pPacket[pi]|=best_factor;
  327. }
  328. }
  329. // END BRUTE FORCE IT
  330. error+=fabs(outdata[data_idx] - indata[data_idx]);
  331. last_value = outdata[data_idx];
  332. }
  333. return( error );
  334. } // compress
  335. bool VectorChannelClass::SaveAdaptiveDelta(ChunkSaveClass & csave, BitChannelClass *binmov)
  336. {
  337. uint32 channelsize = sizeof(W3dAdaptiveDeltaAnimChannelStruct);
  338. int packetsize = sizeof(AdaptiveDeltaPacketStruct);
  339. int numpackets = (MaxFrames + 15) / 16;
  340. channelsize += packetsize * numpackets * VectorLen;
  341. channelsize -= sizeof(char);
  342. channelsize += VectorLen * sizeof(float);
  343. W3dAdaptiveDeltaAnimChannelStruct * chn = (W3dAdaptiveDeltaAnimChannelStruct *)malloc(channelsize);
  344. if (chn == NULL) {
  345. return false;
  346. }
  347. // Brute Force Compressor
  348. // Initialize Chan Data
  349. chn->NumFrames = MaxFrames;
  350. chn->Pivot = ID;
  351. chn->VectorLen = VectorLen;
  352. chn->Flags = Flags;
  353. chn->Scale = 0.0f;
  354. memset(&chn->Data[0], channelsize - (sizeof(W3dAdaptiveDeltaAnimChannelStruct) - sizeof(char)), 0x00);
  355. assert(VectorLen <= 4); // otherwise temp vector won't have room
  356. float *initial = (float *)&chn->Data[0];
  357. float work[4];
  358. // Fetch initial value
  359. for (int i=0; i < VectorLen; i++) {
  360. work[i] = initial[i] = get_value(0, i);
  361. }
  362. float original_packet[16];
  363. float decompressed_packet[16];
  364. float scale = 0.0f;
  365. float last_value=0.0f;
  366. int frame = 1;
  367. float delta;
  368. // Compute Scale
  369. for (int fidx=1; fidx < MaxFrames; fidx++) {
  370. for (i=0; i<VectorLen; i++) {
  371. delta = fabs( get_value(fidx, i) - get_value(fidx - 1, i));
  372. if (delta > scale) scale = delta;
  373. }
  374. }
  375. scale/=7.0f; // range of the delta encode is +- 7 units, in which ever filter range
  376. // the smaller the scale, the better our precision is going to be
  377. // End Compute Scale
  378. for (i=0; i < numpackets; i++) {
  379. for (int vi=0; vi<VectorLen; vi++) {
  380. last_value = work[vi];
  381. // Copy Original Data into the original packet
  382. int temp_frame = frame;
  383. for(int gi=0; gi<16; gi++) {
  384. if (temp_frame < MaxFrames) {
  385. last_value = original_packet[gi] = get_value(temp_frame, vi);
  386. }
  387. else {
  388. original_packet[gi] = last_value;
  389. }
  390. temp_frame++;
  391. } // for gi
  392. // Brute Force Filter
  393. int best_filter = 2 * FILTER_TABLE_SIZE;
  394. float least_error = 999999999.9f;
  395. last_value = work[vi];
  396. for(int try_filter=0; try_filter < FILTER_TABLE_SIZE; try_filter++) {
  397. float temp_error = test_compress(try_filter, scale, last_value, original_packet, decompressed_packet);
  398. if (temp_error < least_error) {
  399. best_filter = try_filter;
  400. least_error = temp_error;
  401. }
  402. }
  403. assert(best_filter < FILTER_TABLE_SIZE);
  404. //log->printf("\nvi= %d frames %d to %d : error = %f ",vi, frame, frame+15, least_error);
  405. // Encode current packet
  406. unsigned char * pPacket;
  407. pPacket = (unsigned char *) &chn->Data[0]; // beginning of data struct
  408. pPacket+= (VectorLen * sizeof(float)); // skip over initial values
  409. pPacket+= (sizeof(AdaptiveDeltaPacketStruct) * VectorLen * ((frame-1)>>4)); // skip up to the appropriate packet
  410. pPacket+= sizeof(AdaptiveDeltaPacketStruct) * vi; // skip up the appropriate vector index
  411. compress(best_filter, scale, last_value, original_packet, pPacket, decompressed_packet);
  412. // update work[vi];
  413. work[vi] = decompressed_packet[15];
  414. } // for vi
  415. frame+=16;
  416. } // for numpackets
  417. // print how big we are vs non-compressed
  418. float rawsize = sizeof(W3dAnimChannelStruct);
  419. rawsize += (VectorLen * sizeof(float32) * (MaxFrames)) - sizeof(float32);
  420. float percent = ((float)channelsize) / rawsize;
  421. percent*=100.0f;
  422. ExportLog::printf("%.0f", percent);
  423. // update final scale
  424. chn->Scale = scale;
  425. if (csave.Write(chn,channelsize) != channelsize) {
  426. return false;
  427. }
  428. if (chn != NULL) {
  429. free(chn);
  430. }
  431. if (!csave.End_Chunk()) {
  432. return false;
  433. }
  434. return true;
  435. } // SaveAdaptiveDelta
  436. bool VectorChannelClass::Save(ChunkSaveClass & csave, BitChannelClass *binmov)
  437. {
  438. if (IsEmpty) return true;
  439. compute_range();
  440. if (End<Begin) {
  441. IsEmpty = true;
  442. return true;
  443. }
  444. if (CompressAnimation) {
  445. // Save the Channel Data compressed
  446. // TIMECODED
  447. if (!csave.Begin_Chunk(W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL)) {
  448. return false;
  449. }
  450. switch (CompressAnimationFlavor)
  451. {
  452. case ANIM_FLAVOR_TIMECODED:
  453. {
  454. return(SaveTimeCoded(csave, binmov));
  455. break;
  456. }
  457. case ANIM_FLAVOR_ADAPTIVE_DELTA:
  458. {
  459. return(SaveAdaptiveDelta(csave, binmov));
  460. break;
  461. }
  462. default:
  463. assert(0); // unknown compressed format
  464. return false;
  465. }
  466. }
  467. else {
  468. // Classic Non Compressed Data
  469. if (!csave.Begin_Chunk(W3D_CHUNK_ANIMATION_CHANNEL)) {
  470. return false;
  471. }
  472. unsigned int channelsize = sizeof(W3dAnimChannelStruct);
  473. channelsize += VectorLen * sizeof(float32) * (MaxFrames) - sizeof(float32);
  474. W3dAnimChannelStruct * chn = (W3dAnimChannelStruct *)malloc(channelsize);
  475. if (chn == NULL) {
  476. return false;
  477. }
  478. chn->FirstFrame = Begin;
  479. chn->LastFrame = End;
  480. chn->VectorLen = VectorLen;
  481. chn->Pivot = ID;
  482. chn->Flags = Flags;
  483. for (int fcount=0; fcount < End-Begin+1; fcount++) {
  484. for (int vidx=0; vidx < VectorLen; vidx++) {
  485. int writeidx = fcount * VectorLen + vidx;
  486. chn->Data[writeidx] = get_value(Begin + fcount,vidx);
  487. }
  488. }
  489. if (csave.Write(chn,channelsize) != channelsize) {
  490. return false;
  491. }
  492. if (chn != NULL) {
  493. free(chn);
  494. }
  495. if (!csave.End_Chunk()) {
  496. return false;
  497. }
  498. }
  499. return true;
  500. }
  501. void VectorChannelClass::SetSaveOptions(bool compress, int flavor, float Terr, float Rerr, bool reduce, int reduce_percent)
  502. {
  503. ReduceAnimation = reduce;
  504. ReduceAnimationPercent = reduce_percent;
  505. CompressAnimation = compress;
  506. CompressAnimationFlavor = flavor;
  507. CompressAnimationTranslationError = Terr;
  508. CompressAnimationRotationError = DEG_TO_RAD(Rerr);
  509. } // SetSaveOptions
  510. //
  511. // Set data in motion channel to identity vector
  512. // R2 - set invisible data to repeat last known position, the previous algorthm caused problems with
  513. // the current movie assets
  514. //
  515. void VectorChannelClass::ClearInvisibleData(BitChannelClass *vis)
  516. {
  517. float *tvec;
  518. assert(VectorLen <= 8);
  519. bool prev_state = vis->Get_Bit( 0 );
  520. tvec = Get_Vector( 0 );
  521. for (int idx=0; idx < MaxFrames; idx++) {
  522. bool cur_state = vis->Get_Bit( idx );
  523. if (cur_state != prev_state) {
  524. prev_state = cur_state;
  525. tvec = Get_Vector( idx );
  526. }
  527. if (false == cur_state) {
  528. //Set_Vector( idx, IdentVect );
  529. Set_Vector( idx, tvec );
  530. }
  531. }
  532. } // ClearInvisibleData
  533. void VectorChannelClass::set_value(int framenum,int vindex,float32 val)
  534. {
  535. assert(framenum >= 0);
  536. assert(framenum < MaxFrames);
  537. assert(vindex >= 0);
  538. assert(vindex < VectorLen);
  539. Data[framenum * VectorLen + vindex] = val;
  540. }
  541. float32 VectorChannelClass::get_value(int framenum,int vindex)
  542. {
  543. assert(framenum >= 0);
  544. assert(framenum < MaxFrames);
  545. assert(vindex >= 0);
  546. assert(vindex < VectorLen);
  547. return Data[framenum * VectorLen + vindex];
  548. }
  549. bool VectorChannelClass::is_identity(float32 * vec)
  550. {
  551. const double ERROR_TOLERANCE = 0.00005 * 0.00005;
  552. double dist = 0.0;
  553. for (int vi=0; vi<VectorLen; vi++) {
  554. dist += (vec[vi] - IdentVect[vi])*(vec[vi] - IdentVect[vi]);
  555. }
  556. // if distance from identity is very small, it is identity...
  557. if (dist < ERROR_TOLERANCE) {
  558. return true;
  559. } else {
  560. return false;
  561. }
  562. }
  563. void VectorChannelClass::compute_range(void)
  564. {
  565. Begin = 0;
  566. while ((Begin < MaxFrames) && (is_identity(Get_Vector(Begin)))) {
  567. Begin++;
  568. }
  569. End = MaxFrames-1;
  570. while ((End >= 0) && (is_identity(Get_Vector(End)))) {
  571. End--;
  572. }
  573. } // compute_range
  574. //
  575. // Remove a packet from a W3dTimeCodedAnimChanelStruct
  576. //
  577. void VectorChannelClass::remove_packet(W3dTimeCodedAnimChannelStruct * c, uint32 packet_idx)
  578. {
  579. assert( c );
  580. assert( c->NumTimeCodes > 1 );
  581. uint32 packet_size = c->VectorLen + 1;
  582. uint32 packet_len = packet_size * sizeof(uint32);
  583. uint32 *src, *dst;
  584. dst = (uint32 *) &c->Data[ packet_size * packet_idx ];
  585. src = (uint32 *) &c->Data[ packet_size * (packet_idx + 1) ];
  586. uint32 copy_length = (c->NumTimeCodes - (packet_idx + 1)) * packet_len;
  587. if (copy_length) {
  588. memcpy(dst, src, copy_length);
  589. }
  590. // Decrement Packet Count
  591. c->NumTimeCodes--;
  592. } // remove_packet
  593. //
  594. // Take a non-compressed TimeCoded Motion Channel
  595. // and compress the packets
  596. //
  597. void VectorChannelClass::compress(W3dTimeCodedAnimChannelStruct * c)
  598. {
  599. assert( c );
  600. // Standard Error Threshold Compression
  601. double Terr = CompressAnimationTranslationError;
  602. double Rerr = CompressAnimationRotationError;
  603. float TimeCodes_ct = c->NumTimeCodes;
  604. switch( c->Flags )
  605. {
  606. case ANIM_CHANNEL_X:
  607. case ANIM_CHANNEL_Y:
  608. case ANIM_CHANNEL_Z: {
  609. while(1) {
  610. uint32 idx = find_useless_packet( c, Terr );
  611. if (PACKETS_ALL_USEFUL == idx) break;
  612. remove_packet( c, idx );
  613. }
  614. break;
  615. }
  616. case ANIM_CHANNEL_XR:
  617. case ANIM_CHANNEL_YR:
  618. case ANIM_CHANNEL_ZR: {
  619. while(1) {
  620. uint32 idx = find_useless_packet( c, Rerr );
  621. if (PACKETS_ALL_USEFUL == idx) break;
  622. remove_packet( c, idx );
  623. }
  624. break;
  625. }
  626. case ANIM_CHANNEL_Q: {
  627. while(1) {
  628. uint32 idx = find_useless_packetQ( c, Rerr );
  629. if (PACKETS_ALL_USEFUL == idx) break;
  630. remove_packet( c, idx );
  631. }
  632. break;
  633. }
  634. default: // undefined channel
  635. assert(0);
  636. break;
  637. }
  638. // Forced Reduction Phase
  639. if (ReduceAnimation) {
  640. if (ReduceAnimationPercent) {
  641. float pct = ReduceAnimationPercent;
  642. pct *= (0.01f);
  643. pct = 1.0f - pct;
  644. // if out of range, don't even try
  645. if (pct <= 0.0f) return;
  646. if (pct >= 1.0f) return;
  647. pct*=TimeCodes_ct;
  648. pct+=0.5f;
  649. uint32 maxFrames = pct;
  650. if (maxFrames < 2) maxFrames = 2;
  651. if (maxFrames >= c->NumTimeCodes) return; // desired minimum already attained
  652. switch( c->Flags )
  653. {
  654. case ANIM_CHANNEL_X:
  655. case ANIM_CHANNEL_Y:
  656. case ANIM_CHANNEL_Z:
  657. case ANIM_CHANNEL_XR:
  658. case ANIM_CHANNEL_YR:
  659. case ANIM_CHANNEL_ZR: {
  660. while(maxFrames < c->NumTimeCodes) {
  661. uint32 idx = find_least_useful_packet( c );
  662. if (PACKETS_ALL_USEFUL == idx) break;
  663. remove_packet( c, idx );
  664. }
  665. break;
  666. }
  667. case ANIM_CHANNEL_Q: {
  668. while(maxFrames < c->NumTimeCodes) {
  669. uint32 idx = find_least_useful_packetQ( c );
  670. if (PACKETS_ALL_USEFUL == idx) break;
  671. remove_packet( c, idx );
  672. }
  673. break;
  674. }
  675. default: // undefined channel
  676. assert(0);
  677. break;
  678. }
  679. } // if ReducePercent
  680. } // if Reduce
  681. } // compress
  682. //
  683. // find a packet that isn't needed, and return the index
  684. // if all packets are necessary, then return back PACKETS_ALL_USEFUL
  685. // a useless packet is defined, as a packet that can be recreated
  686. // via interpolation
  687. //
  688. // Make Sure we NEVER get rid of binary movement packets
  689. // The rule is, you can't interpolate TOO a binary movement, but you can
  690. // interpolate FROM
  691. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  692. //
  693. uint32 VectorChannelClass::find_useless_packet(W3dTimeCodedAnimChannelStruct * c, double tolerance)
  694. {
  695. #define MAX_VECTOR_SIZE 8
  696. static float32 tempvec[MAX_VECTOR_SIZE];
  697. assert( c ); // make sure pointer exists
  698. assert( c->NumTimeCodes ); // make sure some packets exist
  699. assert( c->VectorLen <= MAX_VECTOR_SIZE );
  700. uint32 packet_size = c->VectorLen + 1;
  701. if (c->NumTimeCodes > 1) {
  702. if (c->NumTimeCodes > 2) {
  703. float32 *pVecSrc, *pVecDst, *pVecOriginal;
  704. uint32 *pTcSrc, *pTcDst, *pTcOriginal;
  705. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  706. // Src Pointers
  707. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  708. pVecSrc = (float32 *) pTcSrc+1;
  709. // Original Vector we're trying to recreate
  710. pTcOriginal = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  711. pVecOriginal = (float32 *) pTcOriginal+1;
  712. // Dst Pointers
  713. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  714. pVecDst = (float32 *) pTcDst+1;
  715. // Skip automagically, if binary movement involved
  716. if (*pTcOriginal & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  717. continue; // can't get rid of this guy
  718. }
  719. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  720. continue; // can't get rid of this guy either
  721. }
  722. // Linear Interpolate between Src, and Dst, to recreate the
  723. // Original
  724. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  725. float32 tRecreate = *pTcOriginal;
  726. float32 tEnd = *pTcDst;
  727. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  728. for (uint32 idx=0; idx < c->VectorLen; idx++) {
  729. tempvec[ idx ] = WWMath::Lerp(pVecSrc[idx], pVecDst[idx], tRatio);
  730. }
  731. // Compare Original to our re-creation
  732. bool close_enough = true;
  733. for (idx=0; idx < c->VectorLen; idx++) {
  734. float32 delta;
  735. delta = fabs(pVecOriginal[idx] - tempvec[idx]);
  736. if (delta > tolerance) {
  737. close_enough = false;
  738. break;
  739. }
  740. }
  741. // If our Recreation is very close to the original,
  742. // then discard the original
  743. if (true == close_enough) {
  744. return (try_idx + 1);
  745. }
  746. // else continue
  747. } // for
  748. }
  749. else {
  750. // Special Case, when there are only 2 time codes
  751. // Check to see if they are equal, value
  752. // if so, then return the 2nd timecode as useless
  753. float32 *pVecSrc = (float32 *) &c->Data[ 1 ];
  754. float32 *pVecDst = (float32 *) &c->Data[ packet_size + 1 ];
  755. bool identical = true;
  756. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  757. for(uint32 idx=0; idx < c->VectorLen; idx++) {
  758. float32 delta;
  759. delta = fabs(pVecDst[idx] - pVecSrc[idx]);
  760. if (delta > tolerance) {
  761. identical = false;
  762. break;
  763. }
  764. }
  765. if (identical) return( 1 );
  766. }
  767. }
  768. }
  769. return( PACKETS_ALL_USEFUL );
  770. } // find_useless_packet
  771. //
  772. // Special Case for Quaternion Packets
  773. //
  774. // Make Sure we NEVER get rid of binary movement packets
  775. // The rule is, you can't interpolate TOO a binary movement, but you can
  776. // interpolate FROM
  777. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  778. //
  779. uint32 VectorChannelClass::find_useless_packetQ(W3dTimeCodedAnimChannelStruct * c, double tolerance)
  780. {
  781. assert( c ); // make sure pointer exists
  782. assert( c->NumTimeCodes ); // make sure some packets exist
  783. assert( c->VectorLen == 4);
  784. uint32 packet_size = c->VectorLen + 1;
  785. if (c->NumTimeCodes > 1) {
  786. if (c->NumTimeCodes > 2) {
  787. float32 *pVecSrc, *pVecDst, *pVecOrg;
  788. uint32 *pTcSrc, *pTcDst, *pTcOrg;
  789. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  790. // Src Pointers
  791. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  792. pVecSrc = (float32 *) pTcSrc+1;
  793. // Original Vector we're trying to recreate
  794. pTcOrg = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  795. pVecOrg = (float32 *) pTcOrg+1;
  796. // Dst Pointers
  797. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  798. pVecDst = (float32 *) pTcDst+1;
  799. // Sphereical Linear Interpolate between Src, and Dst, to recreate the
  800. // Original
  801. // Skip automagically, if binary movement involved
  802. if (*pTcOrg & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  803. continue; // can't get rid of this guy
  804. }
  805. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  806. continue; // can't get rid of this guy either
  807. }
  808. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  809. float32 tRecreate = *pTcOrg;
  810. float32 tEnd = *pTcDst;
  811. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  812. Quaternion qSrc(1);
  813. qSrc.Set(pVecSrc[0],pVecSrc[1],pVecSrc[2],pVecSrc[3]);
  814. Quaternion qOrg(1);
  815. qOrg.Set(pVecOrg[0],pVecOrg[1],pVecOrg[2],pVecOrg[3]);
  816. Quaternion qDst(1);
  817. qDst.Set(pVecDst[0],pVecDst[1],pVecDst[2],pVecDst[3]);
  818. Quaternion q = Slerp( qSrc, qDst, tRatio );
  819. Quaternion Delta(1);
  820. Delta = Inverse(qOrg) * q;
  821. double angle = acosf( fabs( Delta.W ) ) * 2.0;
  822. if (angle <= tolerance ) {
  823. return (try_idx + 1);
  824. }
  825. // else continue
  826. } // for
  827. }
  828. }
  829. else {
  830. // Special Case, when there are only 2 time codes
  831. // Check to see if they are equal, value
  832. // if so, then return the 2nd timecode as useless
  833. float32 *pVecSrc = (float32 *) &c->Data[ 1 ];
  834. float32 *pVecDst = (float32 *) &c->Data[ packet_size + 1 ];
  835. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  836. Quaternion qSrc(1);
  837. qSrc.Set(pVecSrc[0], pVecSrc[1], pVecSrc[2], pVecSrc[3]);
  838. Quaternion qDst(1);
  839. qDst.Set(pVecDst[0], pVecDst[1], pVecDst[2], pVecDst[3]);
  840. Quaternion Delta(1);
  841. Delta = Inverse(qSrc) * qDst;
  842. double angle = acosf( fabs( Delta.W ) ) * 2.0;
  843. if (angle <= tolerance ) {
  844. return (1);
  845. }
  846. }
  847. }
  848. return( PACKETS_ALL_USEFUL );
  849. } // find_useless_packetQ
  850. //
  851. // Instead of using a fixed error threshold, find the packet
  852. // that generates the least amount of error, via removal
  853. //
  854. // Make Sure we NEVER get rid of binary movement packets
  855. // The rule is, you can't interpolate too a binary movement, but you can
  856. // interpolate FROM
  857. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  858. //
  859. uint32 VectorChannelClass::find_least_useful_packet(W3dTimeCodedAnimChannelStruct *c)
  860. {
  861. static float32 tempvec[MAX_VECTOR_SIZE];
  862. assert( c ); // make sure pointer exists
  863. assert( c->NumTimeCodes ); // make sure some packets exist
  864. assert( c->VectorLen <= MAX_VECTOR_SIZE );
  865. uint32 packet_size = c->VectorLen + 1;
  866. double leasterror = 9999999.0f;
  867. uint32 ret_idx = PACKETS_ALL_USEFUL;
  868. if (c->NumTimeCodes > 1) {
  869. if (c->NumTimeCodes > 2) {
  870. float32 *pVecSrc, *pVecDst, *pVecOriginal;
  871. uint32 *pTcSrc, *pTcDst, *pTcOriginal;
  872. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  873. // Src Pointers
  874. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  875. pVecSrc = (float32 *) pTcSrc+1;
  876. // Original Vector we're trying to recreate
  877. pTcOriginal = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  878. pVecOriginal = (float32 *) pTcOriginal+1;
  879. // Dst Pointers
  880. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  881. pVecDst = (float32 *) pTcDst+1;
  882. // Skip automagically, if binary movement involved
  883. if (*pTcOriginal & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  884. continue; // can't get rid of this guy
  885. }
  886. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  887. continue; // can't get rid of this guy either
  888. }
  889. // Linear Interpolate between Src, and Dst, to recreate the
  890. // Original
  891. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  892. float32 tRecreate = *pTcOriginal;
  893. float32 tEnd = *pTcDst;
  894. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  895. for (uint32 idx=0; idx < c->VectorLen; idx++) {
  896. tempvec[ idx ] = WWMath::Lerp(pVecSrc[idx], pVecDst[idx], tRatio);
  897. }
  898. // Compare Original to our re-creation
  899. double delta = 0.0;
  900. for (idx=0; idx < c->VectorLen; idx++) {
  901. double tmp;
  902. tmp = pVecOriginal[idx] - tempvec[idx];
  903. delta += (tmp * tmp);
  904. }
  905. delta = sqrtf( delta );
  906. if (delta < leasterror)
  907. {
  908. // If our Recreation is very close to the original,
  909. // then discard the original
  910. leasterror = delta;
  911. ret_idx =(try_idx + 1);
  912. }
  913. // else continue
  914. } // for
  915. return( ret_idx );
  916. }
  917. else {
  918. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  919. return( 1 );
  920. }
  921. }
  922. }
  923. return( PACKETS_ALL_USEFUL );
  924. } // Find Least useful packet
  925. //
  926. // Instead of using a fixed error threshold, find the packet
  927. // that generates the least amount of error, via removal
  928. // special case for Quaternion channel
  929. //
  930. // Make Sure we NEVER get rid of binary movement packets
  931. // The rule is, you can't interpolate FROM a binary movement, but you can
  932. // interpolate TOO
  933. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  934. //
  935. uint32 VectorChannelClass::find_least_useful_packetQ(W3dTimeCodedAnimChannelStruct *c)
  936. {
  937. assert( c ); // make sure pointer exists
  938. assert( c->NumTimeCodes ); // make sure some packets exist
  939. assert( c->VectorLen == 4);
  940. uint32 packet_size = c->VectorLen + 1;
  941. double leasterror = 9999999.0f;
  942. uint32 ret_idx = PACKETS_ALL_USEFUL;
  943. if (c->NumTimeCodes > 1) {
  944. if (c->NumTimeCodes > 2) {
  945. float32 *pVecSrc, *pVecDst, *pVecOrg;
  946. uint32 *pTcSrc, *pTcDst, *pTcOrg;
  947. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  948. // Src Pointers
  949. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  950. pVecSrc = (float32 *) pTcSrc+1;
  951. // Original Vector we're trying to recreate
  952. pTcOrg = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  953. pVecOrg = (float32 *) pTcOrg+1;
  954. // Dst Pointers
  955. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  956. pVecDst = (float32 *) pTcDst+1;
  957. // Skip automagically, if binary movement involved
  958. if (*pTcOrg & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  959. continue; // can't get rid of this guy
  960. }
  961. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  962. continue; // can't get rid of this guy either
  963. }
  964. // Spherical Linear Interpolate between Src, and Dst, to recreate the
  965. // Original
  966. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  967. float32 tRecreate = *pTcOrg;
  968. float32 tEnd = *pTcDst;
  969. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  970. Quaternion qSrc(1);
  971. qSrc.Set(pVecSrc[0],pVecSrc[1],pVecSrc[2],pVecSrc[3]);
  972. Quaternion qOrg(1);
  973. qOrg.Set(pVecOrg[0],pVecOrg[1],pVecOrg[2],pVecOrg[3]);
  974. Quaternion qDst(1);
  975. qDst.Set(pVecDst[0],pVecDst[1],pVecDst[2],pVecDst[3]);
  976. Quaternion q = Slerp( qSrc, qDst, tRatio );
  977. Quaternion Delta(1);
  978. Delta = Inverse(qOrg) * q;
  979. double angle = acosf( fabs( Delta.W ) ) * 2;
  980. if (angle < leasterror ) {
  981. leasterror = angle;
  982. ret_idx = (try_idx + 1);
  983. }
  984. // else continue
  985. } // for
  986. return( ret_idx );
  987. }
  988. }
  989. else {
  990. // Special Case, when there are only 2 time codes
  991. // Check to see if they are equal, value
  992. // if so, then return the 2nd timecode as useless
  993. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  994. return( 1 );
  995. }
  996. }
  997. return( PACKETS_ALL_USEFUL );
  998. } // find_least_useful_packetQ
  999. // EOF - vchannel.cpp