vchannel.cpp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. /*
  2. ** Command & Conquer Renegade(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 12 11/29/01 2:17p 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:: 11/29/01 2:17p $*
  30. * *
  31. * $Revision:: 12 $*
  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. int num_frames = End - Begin + 1;
  474. channelsize += VectorLen * sizeof(float32) * (num_frames) - sizeof(float32);
  475. W3dAnimChannelStruct * chn = (W3dAnimChannelStruct *)malloc(channelsize);
  476. if (chn == NULL) {
  477. return false;
  478. }
  479. chn->FirstFrame = Begin;
  480. chn->LastFrame = End;
  481. chn->VectorLen = VectorLen;
  482. chn->Pivot = ID;
  483. chn->Flags = Flags;
  484. for (int fcount=0; fcount < num_frames; fcount++) {
  485. for (int vidx=0; vidx < VectorLen; vidx++) {
  486. int writeidx = fcount * VectorLen + vidx;
  487. chn->Data[writeidx] = get_value(Begin + fcount,vidx);
  488. }
  489. }
  490. if (csave.Write(chn,channelsize) != channelsize) {
  491. return false;
  492. }
  493. if (chn != NULL) {
  494. free(chn);
  495. }
  496. if (!csave.End_Chunk()) {
  497. return false;
  498. }
  499. }
  500. return true;
  501. }
  502. void VectorChannelClass::SetSaveOptions(bool compress, int flavor, float Terr, float Rerr, bool reduce, int reduce_percent)
  503. {
  504. ReduceAnimation = reduce;
  505. ReduceAnimationPercent = reduce_percent;
  506. CompressAnimation = compress;
  507. CompressAnimationFlavor = flavor;
  508. CompressAnimationTranslationError = Terr;
  509. CompressAnimationRotationError = DEG_TO_RAD(Rerr);
  510. } // SetSaveOptions
  511. //
  512. // Set data in motion channel to identity vector
  513. // R2 - set invisible data to repeat last known position, the previous algorthm caused problems with
  514. // the current movie assets
  515. //
  516. void VectorChannelClass::ClearInvisibleData(BitChannelClass *vis)
  517. {
  518. float *tvec;
  519. assert(VectorLen <= 8);
  520. bool prev_state = vis->Get_Bit( 0 );
  521. tvec = Get_Vector( 0 );
  522. for (int idx=0; idx < MaxFrames; idx++) {
  523. bool cur_state = vis->Get_Bit( idx );
  524. if (cur_state != prev_state) {
  525. prev_state = cur_state;
  526. tvec = Get_Vector( idx );
  527. }
  528. if (false == cur_state) {
  529. //Set_Vector( idx, IdentVect );
  530. Set_Vector( idx, tvec );
  531. }
  532. }
  533. } // ClearInvisibleData
  534. void VectorChannelClass::set_value(int framenum,int vindex,float32 val)
  535. {
  536. assert(framenum >= 0);
  537. assert(framenum < MaxFrames);
  538. assert(vindex >= 0);
  539. assert(vindex < VectorLen);
  540. Data[framenum * VectorLen + vindex] = val;
  541. }
  542. float32 VectorChannelClass::get_value(int framenum,int vindex)
  543. {
  544. assert(framenum >= 0);
  545. assert(framenum < MaxFrames);
  546. assert(vindex >= 0);
  547. assert(vindex < VectorLen);
  548. return Data[framenum * VectorLen + vindex];
  549. }
  550. bool VectorChannelClass::is_identity(float32 * vec)
  551. {
  552. const double ERROR_TOLERANCE = 0.00005 * 0.00005;
  553. double dist = 0.0;
  554. for (int vi=0; vi<VectorLen; vi++) {
  555. dist += (vec[vi] - IdentVect[vi])*(vec[vi] - IdentVect[vi]);
  556. }
  557. // if distance from identity is very small, it is identity...
  558. if (dist < ERROR_TOLERANCE) {
  559. return true;
  560. } else {
  561. return false;
  562. }
  563. }
  564. void VectorChannelClass::compute_range(void)
  565. {
  566. Begin = 0;
  567. while ((Begin < MaxFrames) && (is_identity(Get_Vector(Begin)))) {
  568. Begin++;
  569. }
  570. End = MaxFrames-1;
  571. while ((End >= 0) && (is_identity(Get_Vector(End)))) {
  572. End--;
  573. }
  574. } // compute_range
  575. //
  576. // Remove a packet from a W3dTimeCodedAnimChanelStruct
  577. //
  578. void VectorChannelClass::remove_packet(W3dTimeCodedAnimChannelStruct * c, uint32 packet_idx)
  579. {
  580. assert( c );
  581. assert( c->NumTimeCodes > 1 );
  582. uint32 packet_size = c->VectorLen + 1;
  583. uint32 packet_len = packet_size * sizeof(uint32);
  584. uint32 *src, *dst;
  585. dst = (uint32 *) &c->Data[ packet_size * packet_idx ];
  586. src = (uint32 *) &c->Data[ packet_size * (packet_idx + 1) ];
  587. uint32 copy_length = (c->NumTimeCodes - (packet_idx + 1)) * packet_len;
  588. if (copy_length) {
  589. memcpy(dst, src, copy_length);
  590. }
  591. // Decrement Packet Count
  592. c->NumTimeCodes--;
  593. } // remove_packet
  594. //
  595. // Take a non-compressed TimeCoded Motion Channel
  596. // and compress the packets
  597. //
  598. void VectorChannelClass::compress(W3dTimeCodedAnimChannelStruct * c)
  599. {
  600. assert( c );
  601. // Standard Error Threshold Compression
  602. double Terr = CompressAnimationTranslationError;
  603. double Rerr = CompressAnimationRotationError;
  604. float TimeCodes_ct = c->NumTimeCodes;
  605. switch( c->Flags )
  606. {
  607. case ANIM_CHANNEL_X:
  608. case ANIM_CHANNEL_Y:
  609. case ANIM_CHANNEL_Z: {
  610. while(1) {
  611. uint32 idx = find_useless_packet( c, Terr );
  612. if (PACKETS_ALL_USEFUL == idx) break;
  613. remove_packet( c, idx );
  614. }
  615. break;
  616. }
  617. case ANIM_CHANNEL_XR:
  618. case ANIM_CHANNEL_YR:
  619. case ANIM_CHANNEL_ZR: {
  620. while(1) {
  621. uint32 idx = find_useless_packet( c, Rerr );
  622. if (PACKETS_ALL_USEFUL == idx) break;
  623. remove_packet( c, idx );
  624. }
  625. break;
  626. }
  627. case ANIM_CHANNEL_Q: {
  628. while(1) {
  629. uint32 idx = find_useless_packetQ( c, Rerr );
  630. if (PACKETS_ALL_USEFUL == idx) break;
  631. remove_packet( c, idx );
  632. }
  633. break;
  634. }
  635. default: // undefined channel
  636. assert(0);
  637. break;
  638. }
  639. // Forced Reduction Phase
  640. if (ReduceAnimation) {
  641. if (ReduceAnimationPercent) {
  642. float pct = ReduceAnimationPercent;
  643. pct *= (0.01f);
  644. pct = 1.0f - pct;
  645. // if out of range, don't even try
  646. if (pct <= 0.0f) return;
  647. if (pct >= 1.0f) return;
  648. pct*=TimeCodes_ct;
  649. pct+=0.5f;
  650. uint32 maxFrames = pct;
  651. if (maxFrames < 2) maxFrames = 2;
  652. if (maxFrames >= c->NumTimeCodes) return; // desired minimum already attained
  653. switch( c->Flags )
  654. {
  655. case ANIM_CHANNEL_X:
  656. case ANIM_CHANNEL_Y:
  657. case ANIM_CHANNEL_Z:
  658. case ANIM_CHANNEL_XR:
  659. case ANIM_CHANNEL_YR:
  660. case ANIM_CHANNEL_ZR: {
  661. while(maxFrames < c->NumTimeCodes) {
  662. uint32 idx = find_least_useful_packet( c );
  663. if (PACKETS_ALL_USEFUL == idx) break;
  664. remove_packet( c, idx );
  665. }
  666. break;
  667. }
  668. case ANIM_CHANNEL_Q: {
  669. while(maxFrames < c->NumTimeCodes) {
  670. uint32 idx = find_least_useful_packetQ( c );
  671. if (PACKETS_ALL_USEFUL == idx) break;
  672. remove_packet( c, idx );
  673. }
  674. break;
  675. }
  676. default: // undefined channel
  677. assert(0);
  678. break;
  679. }
  680. } // if ReducePercent
  681. } // if Reduce
  682. } // compress
  683. //
  684. // find a packet that isn't needed, and return the index
  685. // if all packets are necessary, then return back PACKETS_ALL_USEFUL
  686. // a useless packet is defined, as a packet that can be recreated
  687. // via interpolation
  688. //
  689. // Make Sure we NEVER get rid of binary movement packets
  690. // The rule is, you can't interpolate TOO a binary movement, but you can
  691. // interpolate FROM
  692. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  693. //
  694. uint32 VectorChannelClass::find_useless_packet(W3dTimeCodedAnimChannelStruct * c, double tolerance)
  695. {
  696. #define MAX_VECTOR_SIZE 8
  697. static float32 tempvec[MAX_VECTOR_SIZE];
  698. assert( c ); // make sure pointer exists
  699. assert( c->NumTimeCodes ); // make sure some packets exist
  700. assert( c->VectorLen <= MAX_VECTOR_SIZE );
  701. uint32 packet_size = c->VectorLen + 1;
  702. if (c->NumTimeCodes > 1) {
  703. if (c->NumTimeCodes > 2) {
  704. float32 *pVecSrc, *pVecDst, *pVecOriginal;
  705. uint32 *pTcSrc, *pTcDst, *pTcOriginal;
  706. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  707. // Src Pointers
  708. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  709. pVecSrc = (float32 *) pTcSrc+1;
  710. // Original Vector we're trying to recreate
  711. pTcOriginal = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  712. pVecOriginal = (float32 *) pTcOriginal+1;
  713. // Dst Pointers
  714. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  715. pVecDst = (float32 *) pTcDst+1;
  716. // Skip automagically, if binary movement involved
  717. if (*pTcOriginal & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  718. continue; // can't get rid of this guy
  719. }
  720. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  721. continue; // can't get rid of this guy either
  722. }
  723. // Linear Interpolate between Src, and Dst, to recreate the
  724. // Original
  725. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  726. float32 tRecreate = *pTcOriginal;
  727. float32 tEnd = *pTcDst;
  728. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  729. for (uint32 idx=0; idx < c->VectorLen; idx++) {
  730. tempvec[ idx ] = WWMath::Lerp(pVecSrc[idx], pVecDst[idx], tRatio);
  731. }
  732. // Compare Original to our re-creation
  733. bool close_enough = true;
  734. for (idx=0; idx < c->VectorLen; idx++) {
  735. float32 delta;
  736. delta = fabs(pVecOriginal[idx] - tempvec[idx]);
  737. if (delta > tolerance) {
  738. close_enough = false;
  739. break;
  740. }
  741. }
  742. // If our Recreation is very close to the original,
  743. // then discard the original
  744. if (true == close_enough) {
  745. return (try_idx + 1);
  746. }
  747. // else continue
  748. } // for
  749. }
  750. else {
  751. // Special Case, when there are only 2 time codes
  752. // Check to see if they are equal, value
  753. // if so, then return the 2nd timecode as useless
  754. float32 *pVecSrc = (float32 *) &c->Data[ 1 ];
  755. float32 *pVecDst = (float32 *) &c->Data[ packet_size + 1 ];
  756. bool identical = true;
  757. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  758. for(uint32 idx=0; idx < c->VectorLen; idx++) {
  759. float32 delta;
  760. delta = fabs(pVecDst[idx] - pVecSrc[idx]);
  761. if (delta > tolerance) {
  762. identical = false;
  763. break;
  764. }
  765. }
  766. if (identical) return( 1 );
  767. }
  768. }
  769. }
  770. return( PACKETS_ALL_USEFUL );
  771. } // find_useless_packet
  772. //
  773. // Special Case for Quaternion Packets
  774. //
  775. // Make Sure we NEVER get rid of binary movement packets
  776. // The rule is, you can't interpolate TOO a binary movement, but you can
  777. // interpolate FROM
  778. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  779. //
  780. uint32 VectorChannelClass::find_useless_packetQ(W3dTimeCodedAnimChannelStruct * c, double tolerance)
  781. {
  782. assert( c ); // make sure pointer exists
  783. assert( c->NumTimeCodes ); // make sure some packets exist
  784. assert( c->VectorLen == 4);
  785. uint32 packet_size = c->VectorLen + 1;
  786. if (c->NumTimeCodes > 1) {
  787. if (c->NumTimeCodes > 2) {
  788. float32 *pVecSrc, *pVecDst, *pVecOrg;
  789. uint32 *pTcSrc, *pTcDst, *pTcOrg;
  790. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  791. // Src Pointers
  792. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  793. pVecSrc = (float32 *) pTcSrc+1;
  794. // Original Vector we're trying to recreate
  795. pTcOrg = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  796. pVecOrg = (float32 *) pTcOrg+1;
  797. // Dst Pointers
  798. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  799. pVecDst = (float32 *) pTcDst+1;
  800. // Sphereical Linear Interpolate between Src, and Dst, to recreate the
  801. // Original
  802. // Skip automagically, if binary movement involved
  803. if (*pTcOrg & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  804. continue; // can't get rid of this guy
  805. }
  806. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  807. continue; // can't get rid of this guy either
  808. }
  809. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  810. float32 tRecreate = *pTcOrg;
  811. float32 tEnd = *pTcDst;
  812. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  813. Quaternion qSrc(1);
  814. qSrc.Set(pVecSrc[0],pVecSrc[1],pVecSrc[2],pVecSrc[3]);
  815. Quaternion qOrg(1);
  816. qOrg.Set(pVecOrg[0],pVecOrg[1],pVecOrg[2],pVecOrg[3]);
  817. Quaternion qDst(1);
  818. qDst.Set(pVecDst[0],pVecDst[1],pVecDst[2],pVecDst[3]);
  819. Quaternion q = Slerp( qSrc, qDst, tRatio );
  820. Quaternion Delta(1);
  821. Delta = Inverse(qOrg) * q;
  822. double angle = acosf( fabs( Delta.W ) ) * 2.0;
  823. if (angle <= tolerance ) {
  824. return (try_idx + 1);
  825. }
  826. // else continue
  827. } // for
  828. }
  829. }
  830. else {
  831. // Special Case, when there are only 2 time codes
  832. // Check to see if they are equal, value
  833. // if so, then return the 2nd timecode as useless
  834. float32 *pVecSrc = (float32 *) &c->Data[ 1 ];
  835. float32 *pVecDst = (float32 *) &c->Data[ packet_size + 1 ];
  836. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  837. Quaternion qSrc(1);
  838. qSrc.Set(pVecSrc[0], pVecSrc[1], pVecSrc[2], pVecSrc[3]);
  839. Quaternion qDst(1);
  840. qDst.Set(pVecDst[0], pVecDst[1], pVecDst[2], pVecDst[3]);
  841. Quaternion Delta(1);
  842. Delta = Inverse(qSrc) * qDst;
  843. double angle = acosf( fabs( Delta.W ) ) * 2.0;
  844. if (angle <= tolerance ) {
  845. return (1);
  846. }
  847. }
  848. }
  849. return( PACKETS_ALL_USEFUL );
  850. } // find_useless_packetQ
  851. //
  852. // Instead of using a fixed error threshold, find the packet
  853. // that generates the least amount of error, via removal
  854. //
  855. // Make Sure we NEVER get rid of binary movement packets
  856. // The rule is, you can't interpolate too a binary movement, but you can
  857. // interpolate FROM
  858. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  859. //
  860. uint32 VectorChannelClass::find_least_useful_packet(W3dTimeCodedAnimChannelStruct *c)
  861. {
  862. static float32 tempvec[MAX_VECTOR_SIZE];
  863. assert( c ); // make sure pointer exists
  864. assert( c->NumTimeCodes ); // make sure some packets exist
  865. assert( c->VectorLen <= MAX_VECTOR_SIZE );
  866. uint32 packet_size = c->VectorLen + 1;
  867. double leasterror = 9999999.0f;
  868. uint32 ret_idx = PACKETS_ALL_USEFUL;
  869. if (c->NumTimeCodes > 1) {
  870. if (c->NumTimeCodes > 2) {
  871. float32 *pVecSrc, *pVecDst, *pVecOriginal;
  872. uint32 *pTcSrc, *pTcDst, *pTcOriginal;
  873. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  874. // Src Pointers
  875. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  876. pVecSrc = (float32 *) pTcSrc+1;
  877. // Original Vector we're trying to recreate
  878. pTcOriginal = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  879. pVecOriginal = (float32 *) pTcOriginal+1;
  880. // Dst Pointers
  881. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  882. pVecDst = (float32 *) pTcDst+1;
  883. // Skip automagically, if binary movement involved
  884. if (*pTcOriginal & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  885. continue; // can't get rid of this guy
  886. }
  887. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  888. continue; // can't get rid of this guy either
  889. }
  890. // Linear Interpolate between Src, and Dst, to recreate the
  891. // Original
  892. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  893. float32 tRecreate = *pTcOriginal;
  894. float32 tEnd = *pTcDst;
  895. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  896. for (uint32 idx=0; idx < c->VectorLen; idx++) {
  897. tempvec[ idx ] = WWMath::Lerp(pVecSrc[idx], pVecDst[idx], tRatio);
  898. }
  899. // Compare Original to our re-creation
  900. double delta = 0.0;
  901. for (idx=0; idx < c->VectorLen; idx++) {
  902. double tmp;
  903. tmp = pVecOriginal[idx] - tempvec[idx];
  904. delta += (tmp * tmp);
  905. }
  906. delta = sqrtf( delta );
  907. if (delta < leasterror)
  908. {
  909. // If our Recreation is very close to the original,
  910. // then discard the original
  911. leasterror = delta;
  912. ret_idx =(try_idx + 1);
  913. }
  914. // else continue
  915. } // for
  916. return( ret_idx );
  917. }
  918. else {
  919. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  920. return( 1 );
  921. }
  922. }
  923. }
  924. return( PACKETS_ALL_USEFUL );
  925. } // Find Least useful packet
  926. //
  927. // Instead of using a fixed error threshold, find the packet
  928. // that generates the least amount of error, via removal
  929. // special case for Quaternion channel
  930. //
  931. // Make Sure we NEVER get rid of binary movement packets
  932. // The rule is, you can't interpolate FROM a binary movement, but you can
  933. // interpolate TOO
  934. //#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG 0x80000000
  935. //
  936. uint32 VectorChannelClass::find_least_useful_packetQ(W3dTimeCodedAnimChannelStruct *c)
  937. {
  938. assert( c ); // make sure pointer exists
  939. assert( c->NumTimeCodes ); // make sure some packets exist
  940. assert( c->VectorLen == 4);
  941. uint32 packet_size = c->VectorLen + 1;
  942. double leasterror = 9999999.0f;
  943. uint32 ret_idx = PACKETS_ALL_USEFUL;
  944. if (c->NumTimeCodes > 1) {
  945. if (c->NumTimeCodes > 2) {
  946. float32 *pVecSrc, *pVecDst, *pVecOrg;
  947. uint32 *pTcSrc, *pTcDst, *pTcOrg;
  948. for(uint32 try_idx = 0; try_idx < (c->NumTimeCodes - 2); try_idx++) {
  949. // Src Pointers
  950. pTcSrc = (uint32 *) &c->Data[ try_idx * packet_size ];
  951. pVecSrc = (float32 *) pTcSrc+1;
  952. // Original Vector we're trying to recreate
  953. pTcOrg = (uint32 *) &c->Data[ (try_idx + 1) * packet_size ];
  954. pVecOrg = (float32 *) pTcOrg+1;
  955. // Dst Pointers
  956. pTcDst = (uint32 *) &c->Data[ (try_idx + 2 ) * packet_size ];
  957. pVecDst = (float32 *) pTcDst+1;
  958. // Skip automagically, if binary movement involved
  959. if (*pTcOrg & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  960. continue; // can't get rid of this guy
  961. }
  962. if (*pTcDst & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) {
  963. continue; // can't get rid of this guy either
  964. }
  965. // Spherical Linear Interpolate between Src, and Dst, to recreate the
  966. // Original
  967. float32 tStart = ((*pTcSrc) & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG); // upgrade to floats
  968. float32 tRecreate = *pTcOrg;
  969. float32 tEnd = *pTcDst;
  970. float32 tRatio = (tRecreate - tStart) / (tEnd - tStart);
  971. Quaternion qSrc(1);
  972. qSrc.Set(pVecSrc[0],pVecSrc[1],pVecSrc[2],pVecSrc[3]);
  973. Quaternion qOrg(1);
  974. qOrg.Set(pVecOrg[0],pVecOrg[1],pVecOrg[2],pVecOrg[3]);
  975. Quaternion qDst(1);
  976. qDst.Set(pVecDst[0],pVecDst[1],pVecDst[2],pVecDst[3]);
  977. Quaternion q = Slerp( qSrc, qDst, tRatio );
  978. Quaternion Delta(1);
  979. Delta = Inverse(qOrg) * q;
  980. double angle = acosf( fabs( Delta.W ) ) * 2;
  981. if (angle < leasterror ) {
  982. leasterror = angle;
  983. ret_idx = (try_idx + 1);
  984. }
  985. // else continue
  986. } // for
  987. return( ret_idx );
  988. }
  989. }
  990. else {
  991. // Special Case, when there are only 2 time codes
  992. // Check to see if they are equal, value
  993. // if so, then return the 2nd timecode as useless
  994. if ((c->Data[ packet_size ] & W3D_TIMECODED_BINARY_MOVEMENT_FLAG) == 0) {
  995. return( 1 );
  996. }
  997. }
  998. return( PACKETS_ALL_USEFUL );
  999. } // find_least_useful_packetQ
  1000. // EOF - vchannel.cpp