Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
motchan.cpp
Go to the documentation of this file.
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/* $Header: /Commando/Code/ww3d2/motchan.cpp 6 11/29/01 1:07p Jani_p $ */
20/***********************************************************************************************
21 *** Confidential - Westwood Studios ***
22 ***********************************************************************************************
23 * *
24 * Project Name : Commando / G 3D Library *
25 * *
26 * $Archive:: /Commando/Code/ww3d2/motchan.cpp $*
27 * *
28 * Author:: Greg_h *
29 * *
30 * $Modtime:: 11/29/01 1:01p $*
31 * *
32 * $Revision:: 6 $*
33 * *
34 *---------------------------------------------------------------------------------------------*
35 * Functions: *
36 * MotionChannelClass::MotionChannelClass -- constructor *
37 * MotionChannelClass::~MotionChannelClass -- destructor *
38 * MotionChannelClass::Free -- de-allocates all memory in use *
39 * MotionChannelClass::Load -- loads a motion channel from a file *
40 * BitChannelClass::BitChannelClass -- Constructor for BitChannelClass *
41 * BitChannelClass::~BitChannelClass -- Destructor for BitChannelClass *
42 * BitChannelClass::Free -- Free all "external" memory in use *
43 * BitChannelClass::Load -- Read a bit channel from a w3d chunk *
44 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
45
46
47#include "motchan.h"
48#include "w3d_file.h"
49#include "chunkio.h"
50#include "vector.h"
51#include "wwmath.h"
52#include "quat.h"
53#include "wwmath.h"
54//#include <stdio.h>
55//#include <Windows.h>
56// Static Table, for Adaptive Delta Decompressor
57#define FILTER_TABLE_SIZE (256)
58#define FILTER_TABLE_GEN_START (16)
59#define FILTER_TABLE_GEN_SIZE (FILTER_TABLE_SIZE - FILTER_TABLE_GEN_START)
60
61static float filtertable[FILTER_TABLE_SIZE] = {
62 0.00000001f,
63 0.0000001f,
64 0.000001f,
65 0.00001f,
66 0.0001f,
67 0.001f,
68 0.01f,
69 0.1f,
70 1.0f,
71 10.0f,
72 100.0f,
73 1000.0f,
74 10000.0f,
75 100000.0f,
76 1000000.0f,
77 10000000.0f,
78
79};
80static bool table_valid = false;
81
82/***********************************************************************************************
83 * MotionChannelClass::MotionChannelClass -- constructor *
84 * *
85 * INPUT: *
86 * *
87 * OUTPUT: *
88 * *
89 * WARNINGS: *
90 * *
91 * HISTORY: *
92 * 08/11/1997 GH : Created. *
93 *=============================================================================================*/
95 PivotIdx(0),
96 Type(0),
97 VectorLen(0),
98 Data(NULL),
99 FirstFrame(-1),
100 LastFrame(-1),
101 CompressedData(NULL),
102 ValueScale(0.0f),
103 ValueOffset(0.0f)
104{
105}
106
107/***********************************************************************************************
108 * MotionChannelClass::~MotionChannelClass -- destructor *
109 * *
110 * INPUT: *
111 * *
112 * OUTPUT: *
113 * *
114 * WARNINGS: *
115 * *
116 * HISTORY: *
117 * 08/11/1997 GH : Created. *
118 *=============================================================================================*/
120{
121 Free();
122}
123
124/***********************************************************************************************
125 * MotionChannelClass::Free -- de-allocates all memory in use *
126 * *
127 * INPUT: *
128 * *
129 * OUTPUT: *
130 * *
131 * WARNINGS: *
132 * *
133 * HISTORY: *
134 * 08/11/1997 GH : Created. *
135 *=============================================================================================*/
136void MotionChannelClass::Free(void)
137{
138 if (CompressedData) {
139 delete[] CompressedData;
140 CompressedData=NULL;
141 }
142 if (Data) {
143 delete[] Data;
144 Data = NULL;
145 }
146}
147
148
149/***********************************************************************************************
150 * MotionChannelClass::Load -- loads a motion channel from a file *
151 * *
152 * INPUT: *
153 * *
154 * OUTPUT: *
155 * *
156 * WARNINGS: *
157 * *
158 * HISTORY: *
159 * 08/11/1997 GH : Created. *
160 *=============================================================================================*/
162{
163 int size = cload.Cur_Chunk_Length();
164 // There was a bug in the exporter which saved too much data, so let's try and not load everything.
165 unsigned int saved_datasize = (size - sizeof(W3dAnimChannelStruct));
166
168 if (cload.Read(&chan,sizeof(W3dAnimChannelStruct)) != sizeof(W3dAnimChannelStruct)) {
169 return false;
170 }
171
172 FirstFrame = chan.FirstFrame;
173 LastFrame = chan.LastFrame;
174 VectorLen = chan.VectorLen;
175 Type = chan.Flags;
176 PivotIdx = chan.Pivot;
177
178 unsigned int num_floats = LastFrame-FirstFrame+1;//(datasize / sizeof(float32)) + 1;
179 num_floats*=VectorLen;
180 unsigned int datasize=(num_floats-1)*sizeof(float);
181
182 Data = MSGW3DNEWARRAY("MotionChannelClass::Data") float32[num_floats];
183 Data[0] = chan.Data[0];
184
185 if (cload.Read(&(Data[1]),datasize) != datasize) {
186 Free();
187 return false;
188 }
189 // Skip over the extra data at the end of the chunk (saved by an error in the exporter)
190 if (saved_datasize-datasize>0) {
191 cload.Seek(saved_datasize-datasize);
192 }
193
194 Do_Data_Compression(datasize);
195 return true;
196}
197
198
199
200/***********************************************************************************************
201 * BitChannelClass::BitChannelClass -- Constructor for BitChannelClass *
202 * *
203 * INPUT: *
204 * *
205 * OUTPUT: *
206 * *
207 * WARNINGS: *
208 * *
209 * HISTORY: *
210 *=============================================================================================*/
212 PivotIdx(0),
213 Type(0),
214 DefaultVal(0),
215 FirstFrame(-1),
216 LastFrame(-1),
217 Bits(NULL)
218{
219}
220
221
222/***********************************************************************************************
223 * BitChannelClass::~BitChannelClass -- Destructor for BitChannelClass *
224 * *
225 * INPUT: *
226 * *
227 * OUTPUT: *
228 * *
229 * WARNINGS: *
230 * *
231 * HISTORY: *
232 * 1/21/98 GTH : Created. *
233 *=============================================================================================*/
235{
236 Free();
237}
238
239
240/***********************************************************************************************
241 * BitChannelClass::Free -- Free all "external" memory in use *
242 * *
243 * INPUT: *
244 * *
245 * OUTPUT: *
246 * *
247 * WARNINGS: *
248 * *
249 * HISTORY: *
250 * 1/21/98 GTH : Created. *
251 *=============================================================================================*/
252void BitChannelClass::Free(void)
253{
254 if (Bits != NULL) {
255 delete[] Bits;
256 Bits = NULL;
257 }
258}
259
260
261/***********************************************************************************************
262 * BitChannelClass::Load -- Read a bit channel from a w3d chunk *
263 * *
264 * INPUT: *
265 * *
266 * OUTPUT: *
267 * *
268 * WARNINGS: *
269 * *
270 * HISTORY: *
271 * 1/21/98 GTH : Created. *
272 *=============================================================================================*/
274{
275 Free();
276
277 int chunk_size = cload.Cur_Chunk_Length();
278
280 if (cload.Read(&chan,sizeof(W3dBitChannelStruct)) != sizeof(W3dBitChannelStruct)) {
281 return false;
282 }
283
284 FirstFrame = chan.FirstFrame;
285 LastFrame = chan.LastFrame;
286 Type = chan.Flags;
287 PivotIdx = chan.Pivot;
288 DefaultVal = chan.DefaultVal;
289
290 uint32 numbits = LastFrame - FirstFrame + 1;
291 uint32 numbytes = (numbits + 7) / 8;
292 uint32 bytesleft = numbytes - 1;
293
294 assert((sizeof(W3dBitChannelStruct) + bytesleft) == (unsigned)chunk_size);
295
296 Bits = MSGW3DNEWARRAY("BitChannelClass::Bits") uint8[numbytes];
297 assert(Bits);
298
299 Bits[0] = chan.Data[0];
300
301 if (bytesleft > 0) {
302 if (cload.Read(&(Bits[1]),bytesleft) != bytesleft) {
303 Free();
304 return false;
305 }
306 }
307
308 return true;
309}
310
311
312/***********************************************************************************************
313 * TimeCodedMotionChannelClass::TimeCodedMotionChannelClass -- constructor *
314 * *
315 * INPUT: *
316 * *
317 * OUTPUT: *
318 * *
319 * WARNINGS: *
320 * *
321 * HISTORY: *
322 * 08/11/1997 GH : Created. *
323 *=============================================================================================*/
325 PivotIdx(0),
326 Type(0),
327 VectorLen(0),
328 PacketSize(0),
329 Data(NULL),
330 NumTimeCodes(0),
331 LastTimeCodeIdx(0), // absolute index to last time code
332 CachedIdx(0) // Last Index Used
333{
334}
335
336/***********************************************************************************************
337 * MotionChannelClass::~MotionChannelClass -- destructor *
338 * *
339 * INPUT: *
340 * *
341 * OUTPUT: *
342 * *
343 * WARNINGS: *
344 * *
345 * HISTORY: *
346 * 08/11/1997 GH : Created. *
347 *=============================================================================================*/
352
353/***********************************************************************************************
354 * TimeCodedMotionChannelClass::Free -- de-allocates all memory in use *
355 * *
356 * INPUT: *
357 * *
358 * OUTPUT: *
359 * *
360 * WARNINGS: *
361 * *
362 * HISTORY: *
363 * 08/11/1997 GH : Created. *
364 *=============================================================================================*/
365void TimeCodedMotionChannelClass::Free(void)
366{
367 if (Data) {
368 delete[] Data;
369 Data = NULL;
370 }
371}
372
373
374/***********************************************************************************************
375 * TimeCodedMotionChannelClass::Load -- loads a motion channel from a file *
376 * *
377 * INPUT: *
378 * *
379 * OUTPUT: *
380 * *
381 * WARNINGS: *
382 * *
383 * HISTORY: *
384 * 08/11/1997 GH : Created. *
385 *=============================================================================================*/
387{
388 int size = cload.Cur_Chunk_Length();
389 unsigned int datasize = size - sizeof(W3dTimeCodedAnimChannelStruct);
390 unsigned int numInts = (datasize / sizeof(uint32)) + 1;
391
393 if (cload.Read(&chan,sizeof(W3dTimeCodedAnimChannelStruct)) != sizeof(W3dTimeCodedAnimChannelStruct)) {
394 return false;
395 }
396
397 NumTimeCodes = chan.NumTimeCodes;
398 VectorLen = chan.VectorLen;
399 Type = chan.Flags;
400 PivotIdx = chan.Pivot;
401 PacketSize = VectorLen+1;
402 CachedIdx = 0;
403 LastTimeCodeIdx = (NumTimeCodes-1) * PacketSize;
404
405 Data = MSGW3DNEWARRAY("TimeCodedMotionChannelClass::Data") uint32[numInts];
406 Data[0] = chan.Data[0];
407
408 if (cload.Read(&(Data[1]), datasize) != datasize) {
409 Free();
410 return false;
411 }
412 return true;
413}
414
415
416/***********************************************************************************************
417 * TimeCodedMotionChannelClass::Get_Vector -- returns the vector for the specified frame # *
418 * *
419 * INPUT: *
420 * *
421 * OUTPUT: *
422 * *
423 * WARNINGS: *
424 * *
425 * HISTORY: *
426 * 08/11/1997 GH : Created. *
427 *=============================================================================================*/
429{
430
431 uint32 tc0;
432
433 tc0 = frame;
434
435 uint32 pidx = get_index( tc0 );
436 uint32 p2idx;
437
438 if (pidx == ((NumTimeCodes - 1) * PacketSize)) {
439
440 float32 *frm = (float32 *) &Data[pidx+1];
441
442 for (int i=0; i < VectorLen; i++) {
443
444 setvec[i] = frm[i];
445
446 }
447
448 return;
449
450 }
451 else {
452 p2idx = pidx + PacketSize;
453 }
454
455 uint32 time = Data[p2idx];
456
458 float32 *frm = (float32 *) &Data[pidx+1];
459 for (int i=0; i < VectorLen; i++) {
460 setvec[i] = frm[i];
461 }
462 return;
463 }
464
465 float32 time1 = (Data[pidx] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG);
467
468 float32 ratio = (frame - time1) / (time2 - time1);
469
470 float32 *frame1 = (float32 *) &Data[pidx+1];
471 float32 *frame2 = (float32 *) &Data[p2idx+1];
472
473 for (int i=0; i < VectorLen; i++) {
474
475 setvec[i] = WWMath::Lerp(frame1[i],frame2[i],ratio);
476
477 }
478
479} // Get_Vector
480
481
483{
484
485 assert(VectorLen == 4);
486
487 Quaternion q(1);
488
489 uint32 tc0;
490
491 tc0 = frame;
492
493 uint32 pidx = get_index( tc0 );
494 uint32 p2idx;
495
496 if (pidx == ((NumTimeCodes - 1) * PacketSize)) {
497
498 float32 *vec = (float32 *) &Data[pidx+1];
499
500 q.Set(vec[0], vec[1], vec[2], vec[3]);
501
502 return( q );
503
504 }
505 else {
506 p2idx = pidx + PacketSize;
507 }
508
509 uint32 time = Data[p2idx];
510
512 // its a binary movement!
513 float32 *vec = (float32 *) &Data[pidx+1];
514
515 q.Set(vec[0], vec[1], vec[2], vec[3]);
516
517 return( q );
518 }
519
520 float32 time1 = (Data[pidx] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG);
522
523 float32 ratio = (frame - time1) / (time2 - time1);
524
525 float32 *frame1 = (float32 *) &Data[pidx+1];
526 float32 *frame2 = (float32 *) &Data[p2idx+1];
527
528 Quaternion q1(1);
529 Quaternion q2(1);
530
531 q1.Set(frame1[0], frame1[1], frame1[2], frame1[3]);
532 q2.Set(frame2[0], frame2[1], frame2[2], frame2[3]);
533
534 Fast_Slerp(q, q1, q2, ratio);
535
536 return( q );
537
538} // Get_QuatVector
539
540
541
542/***********************************************************************************************
543 * TimeCodedMotionChannelClass::binary_search_index / returns packet index *
544 * *
545 * INPUT: *
546 * *
547 * OUTPUT: *
548 * *
549 * WARNINGS: *
550 * *
551 * HISTORY: *
552 * 01/27/2000 JGA : Created. *
553 *=============================================================================================*/
554// New version that uses a binary search, and no cache
555uint32 TimeCodedMotionChannelClass::binary_search_index(uint32 timecode)
556{
557 int leftIdx = 0;
558 int rightIdx = NumTimeCodes - 2;
559 int dx;
560 uint32 time;
561
562
563 int idx = LastTimeCodeIdx; //((rightIdx+1) * PacketSize;)
564
565 //int32 LastTimeCodeIdx; // absolute index to last time code
566 //int32 CachedIdx; // Last Index Used
567
568 // special case last packet
569 time = Data[idx] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
570 if (timecode >= time) return(idx);
571
572 for (;;) {
573
574 dx = rightIdx - leftIdx;
575
576 dx>>=1; // divide by 2
577
578 dx += leftIdx;
579
580 idx = dx * PacketSize;
581
582 time = Data[idx] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
583
584 if (timecode < time) {
585 rightIdx = dx;
586 continue;
587 }
588
589 time = Data[idx + PacketSize] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
590
591 if (timecode < time) return(idx);
592
593 if (leftIdx ^ dx) {
594 leftIdx = dx;
595 continue;
596 }
597
598 //
599 // if leftIdx == dx prior to assignment, then leftIdx is stuck.
600 //
601
602 leftIdx++;
603
604 }
605
606 assert(0);
607 return(0);
608
609} // binary_search_index
610
611
612/***********************************************************************************************
613 * TimeCodedMotionChannelClass::get_index / returns packet index *
614 * *
615 * INPUT: *
616 * *
617 * OUTPUT: *
618 * *
619 * WARNINGS: *
620 * *
621 * HISTORY: *
622 * 01/27/2000 JGA : Created. *
623 *=============================================================================================*/
624uint32 TimeCodedMotionChannelClass::get_index(uint32 timecode)
625{
626 assert(CachedIdx <= LastTimeCodeIdx);
627
628 uint32 time;
629
630 time = Data[CachedIdx] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
631
632 if (timecode >= time) {
633 // possibly in the current packet
634
635 // special case for end packets
636 if (CachedIdx == LastTimeCodeIdx) return(CachedIdx);
637 time = Data[CachedIdx + PacketSize] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
638 if (timecode < time) return(CachedIdx);
639
640 // Do one time look-ahead before reverting to a search
641 CachedIdx+=PacketSize;
642 if (CachedIdx == LastTimeCodeIdx) return(CachedIdx);
643 time = Data[CachedIdx + PacketSize] & ~W3D_TIMECODED_BINARY_MOVEMENT_FLAG;
644 if (timecode < time) return(CachedIdx);
645 }
646
647 CachedIdx = binary_search_index( timecode );
648
649 return(CachedIdx);
650
651} // get_index
652
653/***********************************************************************************************
654 * TimeCodedMotionChannelClass::set_identity -- returns an "identity" vector (not really...hmm...) *
655 * *
656 * INPUT: *
657 * *
658 * OUTPUT: *
659 * *
660 * WARNINGS: *
661 * *
662 * HISTORY: *
663 * 08/11/1997 GH : Created. *
664 *=============================================================================================*/
665void TimeCodedMotionChannelClass::set_identity(float * setvec)
666{
667 if (Type == ANIM_CHANNEL_Q) {
668
669 setvec[0] = 0.0f;
670 setvec[1] = 0.0f;
671 setvec[2] = 0.0f;
672 setvec[3] = 1.0f;
673
674 } else {
675
676 setvec[0] = 0.0f;
677
678 }
679} // set_identity
680
681
682/***********************************************************************************************
683 * TimeCodedBitChannelClass::TimeCodedBitChannelClass -- Constructor for BitChannelClass *
684 * *
685 * INPUT: *
686 * *
687 * OUTPUT: *
688 * *
689 * WARNINGS: *
690 * *
691 * HISTORY: *
692 *=============================================================================================*/
694 PivotIdx(0),
695 Type(0),
696 DefaultVal(0),
697 Bits(NULL),
698 CachedIdx(0)
699{
700}
701
702
703/***********************************************************************************************
704 * TimeCodedBitChannelClass::~TimeCodedBitChannelClass -- Destructor for BitChannelClass *
705 * *
706 * INPUT: *
707 * *
708 * OUTPUT: *
709 * *
710 * WARNINGS: *
711 * *
712 * HISTORY: *
713 * 1/21/98 GTH : Created. *
714 *=============================================================================================*/
719
720
721/***********************************************************************************************
722 * TimeCodedBitChannelClass::Free -- Free all "external" memory in use *
723 * *
724 * INPUT: *
725 * *
726 * OUTPUT: *
727 * *
728 * WARNINGS: *
729 * *
730 * HISTORY: *
731 * 1/21/98 GTH : Created. *
732 *=============================================================================================*/
733void TimeCodedBitChannelClass::Free(void)
734{
735 if (Bits != NULL) {
736 delete[] Bits;
737 Bits = NULL;
738 }
739}
740
741
742/***********************************************************************************************
743 * TimeCodedBitChannelClass::Load -- Read a bit channel from a w3d chunk *
744 * *
745 * INPUT: *
746 * *
747 * OUTPUT: *
748 * *
749 * WARNINGS: *
750 * *
751 * HISTORY: *
752 * 1/21/98 GTH : Created. *
753 *=============================================================================================*/
755{
756 Free();
757
758 int chunk_size = cload.Cur_Chunk_Length();
759
761 if (cload.Read(&chan,sizeof(W3dTimeCodedBitChannelStruct)) != sizeof(W3dTimeCodedBitChannelStruct)) {
762 return false;
763 }
764
765 NumTimeCodes = chan.NumTimeCodes;
766 Type = chan.Flags;
767 PivotIdx = chan.Pivot;
768 DefaultVal = chan.DefaultVal;
769 CachedIdx = 0;
770
771 uint32 bytesleft = (NumTimeCodes - 1) * sizeof(uint32);
772
773 assert((sizeof(W3dTimeCodedBitChannelStruct) + bytesleft) == (unsigned)chunk_size);
774
775 Bits = MSGW3DNEWARRAY("TimeCodedBitChannelClass::Bits") uint32[NumTimeCodes];
776 assert(Bits);
777
778 Bits[0] = chan.Data[0];
779
780 if (bytesleft > 0) {
781 if (cload.Read(&(Bits[1]),bytesleft) != bytesleft) {
782 Free();
783 return false;
784 }
785 }
786
787 return true;
788} // Load_W3D
789
790
791/***********************************************************************************************
792 * TimeCodedBitChannelClass::Get_Bit -- Lookup a bit in the bit channel *
793 * *
794 * INPUT: *
795 * *
796 * OUTPUT: *
797 * *
798 * WARNINGS: *
799 * *
800 * HISTORY: *
801 * 1/21/98 GTH : Created. *
802 *=============================================================================================*/
804{
805 assert(frame >= 0);
806 assert(CachedIdx < NumTimeCodes);
807
808 int time;
809 int idx=0;
810
811 time = Bits[CachedIdx] & ~W3D_TIMECODED_BIT_MASK;
812
813
814 if (frame >= time) {
815
816 // start from here
817 idx = CachedIdx+1;
818
819 }
820
821 for (;idx < (int) NumTimeCodes ; idx++) {
822
823 time = Bits[idx] &~W3D_TIMECODED_BIT_MASK;
824
825 if (frame < time) break;
826
827 }
828
829 idx--;
830
831 if (idx < 0) idx = 0;
832
833 CachedIdx = idx;
834
835 return (((Bits[idx] & W3D_TIMECODED_BIT_MASK) == W3D_TIMECODED_BIT_MASK));
836
837} // Get_Bit
838
839
840// Begin Adaptive Delta
841
842
843/***********************************************************************************************
844 * AdaptiveDeltaMotionChannelClass::AdaptiveDeltaMotionChannelClass -- constructor *
845 * *
846 * INPUT: *
847 * *
848 * OUTPUT: *
849 * *
850 * WARNINGS: *
851 * *
852 * HISTORY: *
853 * 02/18/2000 JGA : Created. *
854 *=============================================================================================*/
856 PivotIdx(0),
857 Type(0),
858 VectorLen(0),
859 Data(NULL),
860 NumFrames(0),
861 CacheData(NULL),
862 Scale(0.0f)
863{
864
865 if (false == table_valid) {
866 // Create Filter Table, used in delta compression
867
868 for (int i=0; i<FILTER_TABLE_GEN_SIZE; i++)
869 {
870 float ratio = i;
871
872 //ratio = ((ratio + 1.0f) / 128.0f);
873 ratio/=((float) FILTER_TABLE_GEN_SIZE);
874
875 filtertable[i + FILTER_TABLE_GEN_START] = 1.0f - WWMath::Sin( DEG_TO_RAD(90.0f * ratio));
876 }
877
878 table_valid = true;
879
880 }
881
882}
883
884/***********************************************************************************************
885 * MotionChannelClass::~MotionChannelClass -- destructor *
886 * *
887 * INPUT: *
888 * *
889 * OUTPUT: *
890 * *
891 * WARNINGS: *
892 * *
893 * HISTORY: *
894 * 02/18/1000 JGA : Created. *
895 *=============================================================================================*/
900
901/***********************************************************************************************
902 * AdaptiveDeltaMotionChannelClass::Free -- de-allocates all memory in use *
903 * *
904 * INPUT: *
905 * *
906 * OUTPUT: *
907 * *
908 * WARNINGS: *
909 * *
910 * HISTORY: *
911 * 02/18/2000 JGA : Created. *
912 *=============================================================================================*/
913void AdaptiveDeltaMotionChannelClass::Free(void)
914{
915 if (Data) {
916 delete[] Data;
917 Data = NULL;
918 }
919
920 if (CacheData) {
921 delete CacheData;
922 CacheData = NULL;
923 }
924
925} // Free
926
927
928/***********************************************************************************************
929 * AdaptiveDeltaMotionChannelClass::Load -- loads a motion channel from a file *
930 * *
931 * INPUT: *
932 * *
933 * OUTPUT: *
934 * *
935 * WARNINGS: *
936 * *
937 * HISTORY: *
938 * 02/18/2000 JGA : Created. *
939 *=============================================================================================*/
941{
942 int size = cload.Cur_Chunk_Length();
943 unsigned int datasize = size - sizeof(W3dAdaptiveDeltaAnimChannelStruct);
944 unsigned int numInts = (datasize / sizeof(uint32)) + 1;
945
948 return false;
949 }
950
951 VectorLen = chan.VectorLen;
952 Type = chan.Flags;
953 PivotIdx = chan.Pivot;
954 NumFrames = chan.NumFrames;
955 Scale = chan.Scale;
956 CacheFrame = 0x7FFFFFFF; // a big number, so we know its not valid
957 CacheData = MSGW3DNEWARRAY("AdaptiveDeltaMotionChannelClass::CacheData") float[VectorLen * 2]; // cacheframe & cachedframe+1 by VectorLen
958
959 Data = MSGW3DNEWARRAY("AdaptiveDeltaMotionChannelClass::Data") uint32[numInts];
960 Data[0] = chan.Data[0];
961
962 if (cload.Read(&(Data[1]), datasize) != datasize) {
963 Free();
964 return false;
965 }
966 return true;
967
968} // Load_W3D
969
970
971/***********************************************************************************************
972 * AdaptiveDeltaMotionChannelClass::decompress *
973 * *
974 * INPUT: *
975 * *
976 * OUTPUT: *
977 * *
978 * WARNINGS: *
979 * *
980 * HISTORY: *
981 * 02/23/2000 JGA : Created. *
982 *=============================================================================================*/
983#define PACKET_SIZE (9)
984void AdaptiveDeltaMotionChannelClass::decompress(uint32 frame_idx, float *outdata)
985{
986 // Start Over from the beginning
987 float *base = (float *) &Data[0]; // pointer to our true know beginning values
988
989 bool done = false;
990
991 for(int vi=0; vi<VectorLen; vi++) {
992 // Decompress all the vector indices, since they will probably all be needed
993 unsigned char *pPacket = (unsigned char *) Data; // pointer to current packet
994 pPacket+= (sizeof(float) * VectorLen); // skip non-compressed header information
995 pPacket+= PACKET_SIZE * vi; // skip to the appropriate packet start
996
997 float last_value = base[vi];
998
999 for (uint32 frame=1; frame<=frame_idx;) {
1000 // Frame Loop
1001 uint32 filter_index = *pPacket; // packet header
1002
1003 pPacket++; // skip to nybble compressed data
1004
1005 float filter = filtertable[filter_index] * Scale; // decompression filter
1006
1007 // data is grouped in sets of 16 nybbles
1008 for (int fi=0; fi < 16; fi++) {
1009
1010 int pi = fi>>1; // create packet index
1011
1012 int factor; // factor, contains extracted nybble -8 to +7
1013
1014 if (fi & 1) {
1015 factor = pPacket[pi];
1016 factor>>=4;
1017 }
1018 else {
1019 factor = pPacket[pi];
1020 }
1021
1022 // Sign Extend
1023 factor &=0xF;
1024 if (factor & 0x8) {
1025 factor |= 0xFFFFFFF0;
1026 }
1027
1028 // Convert to Floating Point
1029
1030 float ffactor = factor;
1031
1032 float delta = ffactor * filter;
1033
1034 last_value+=delta;
1035
1036 if (frame == frame_idx) {
1037 done = true;
1038 break;
1039 }
1040 frame++;
1041
1042 } // for fi < 16
1043
1044 if (done) break; // we're at the desired frame
1045
1046 pPacket+= ((PACKET_SIZE * VectorLen) - 1); // skip to next packet
1047
1048 } // for frame_idx
1049
1050 outdata[vi] = last_value;
1051
1052 } // for vi=0; vi < 4
1053
1054} // decompress, from beginning
1055
1056void AdaptiveDeltaMotionChannelClass::decompress(uint32 src_idx, float *srcdata, uint32 frame_idx, float *outdata)
1057{
1058 // Contine decompressing from src_idx, up to frame_idx
1059
1060 assert(src_idx < frame_idx);
1061 src_idx++;
1062
1063 float *base = (float *) &Data[0]; // pointer to our true know beginning values
1064 base += VectorLen; // skip header information
1065
1066 bool done = false;
1067
1068 for(int vi=0; vi<VectorLen; vi++) {
1069 // Decompress all the vector indices, since they will probably all be needed
1070 unsigned char *pPacket = (unsigned char *) base; // pointer to current packet
1071 pPacket+= PACKET_SIZE * vi; // skip to the appropriate packet start
1072 pPacket+= (PACKET_SIZE * VectorLen) * ((src_idx-1)>>4); // skip out to current packet
1073
1074 // initial filter index
1075 int fi = (src_idx-1) & 0xF;
1076
1077 float last_value = srcdata[vi];
1078
1079 for (uint32 frame=src_idx; frame<=frame_idx;) {
1080 // Frame Loop
1081 uint32 filter_index = *pPacket; // packet header
1082
1083 pPacket++; // skip to nybble compressed data
1084
1085 float filter = filtertable[filter_index] * Scale; // decompression filter
1086
1087 // data is grouped in sets of 16 nybbles
1088 for (fi; fi < 16; fi++) {
1089
1090 int pi = fi>>1; // create packet index
1091
1092 int factor; // factor, contains extracted nybble -8 to +7
1093
1094 if (fi & 1) {
1095 factor = pPacket[pi];
1096 factor>>=4;
1097 }
1098 else {
1099 factor = pPacket[pi];
1100 }
1101
1102 // Sign Extend
1103 factor &=0xF;
1104 if (factor & 0x8) {
1105 factor |= 0xFFFFFFF0;
1106 }
1107
1108 // Convert to Floating Point
1109
1110 float ffactor = factor;
1111
1112 float delta = ffactor * filter;
1113
1114 last_value+=delta;
1115
1116 if (frame == frame_idx) {
1117 done = true;
1118 break;
1119 }
1120 frame++;
1121
1122 } // for fi < 16
1123 fi = 0;
1124
1125 if (done) break; // we're at the desired frame
1126
1127 pPacket+= ((PACKET_SIZE * VectorLen) - 1); // skip to next packet
1128
1129 } // for frame_idx
1130
1131 outdata[vi] = last_value;
1132
1133 } // for vi=0; vi < 4
1134
1135} // decompress, from continuation
1136
1137
1138/***********************************************************************************************
1139 * AdaptiveDeltaMotionChannelClass::getframe returns decompressed data for frame/vectorindex *
1140 * *
1141 * INPUT: *
1142 * *
1143 * OUTPUT: *
1144 * *
1145 * WARNINGS: *
1146 * *
1147 * HISTORY: *
1148 * 02/18/2000 JGA : Created. *
1149 *=============================================================================================*/
1150float AdaptiveDeltaMotionChannelClass::getframe(uint32 frame_idx, uint32 vector_idx)
1151{
1152 // Make sure frame_idx is valid
1153
1154 if (frame_idx >= NumFrames) frame_idx = NumFrames - 1;
1155
1156 // Check to see if the data is already in cache?
1157
1158 if (CacheFrame == frame_idx) {
1159 return(CacheData[vector_idx]);
1160 }
1161
1162 if ((CacheFrame+1) == frame_idx) {
1163 return(CacheData[vector_idx + VectorLen]);
1164 }
1165
1166 if (frame_idx < CacheFrame) {
1167 // Requested Frame isn't cached, so cache it, and frame_idx+1, and return the decompressed data
1168 // from frame_idx
1169
1170 decompress(frame_idx, &CacheData[0]);
1171
1172 if (frame_idx != (NumFrames - 1)) {
1173 decompress(frame_idx, &CacheData[0], frame_idx+1, &CacheData[VectorLen]);
1174 }
1175
1176 CacheFrame = frame_idx;
1177
1178 return(CacheData[vector_idx]);
1179 }
1180
1181 // Copy last known Cached data down
1182
1183 if (frame_idx == (CacheFrame + 2)) {
1184
1185 // Sliding window
1186 memcpy(&CacheData[0], &CacheData[VectorLen], VectorLen * sizeof(float));
1187
1188 CacheFrame++;
1189
1190 decompress(CacheFrame, &CacheData[0], frame_idx, &CacheData[VectorLen]);
1191
1192 return(CacheData[VectorLen + vector_idx]);
1193 }
1194
1195 // Else just use last known frame to decompress forwards
1196
1197 assert(VectorLen <= 4);
1198
1199 float temp[4];
1200
1201 memcpy(&temp[0], &CacheData[VectorLen], VectorLen * sizeof(float));
1202
1203 decompress(CacheFrame, &temp[0], frame_idx, &CacheData[0]);
1204 CacheFrame = frame_idx;
1205
1206 if (frame_idx != (NumFrames - 1)) {
1207 decompress(CacheFrame, &CacheData[0], frame_idx+1, &CacheData[VectorLen]);
1208 }
1209
1210 return(CacheData[vector_idx]);
1211
1212} // getframe
1213
1214/***********************************************************************************************
1215 * AdaptiveDeltaMotionChannelClass::Get_Vector -- returns the vector for the specified frame # *
1216 * *
1217 * INPUT: *
1218 * *
1219 * OUTPUT: *
1220 * *
1221 * WARNINGS: *
1222 * *
1223 * HISTORY: *
1224 * 02/18/2000 JGA : Created. *
1225 *=============================================================================================*/
1227{
1228
1229 uint32 frame1 = frame;
1230
1231 float ratio = frame - frame1;
1232
1233 float value1 = getframe(frame1);
1234 float value2 = getframe(frame1 + 1);
1235
1236 *setvec = WWMath::Lerp(value1,value2,ratio);
1237
1238
1239} // Get_Vector
1240
1241
1242//
1243// Special Case Quats, so we can use Slerp
1244//
1246{
1247
1248 uint32 frame1 = frame;
1249 uint32 frame2 = frame1+1;
1250 float ratio = frame - frame1;
1251
1252 Quaternion q1(1);
1253 q1.Set( getframe(frame1, 0),
1254 getframe(frame1, 1),
1255 getframe(frame1, 2),
1256 getframe(frame1, 3) );
1257
1258 Quaternion q2(1);
1259
1260 q2.Set( getframe(frame2, 0),
1261 getframe(frame2, 1),
1262 getframe(frame2, 2),
1263 getframe(frame2, 3) );
1264
1265
1266 Quaternion q(1);
1267
1268 Fast_Slerp(q, q1, q2, ratio);
1269
1270 return( q );
1271
1272} // Get_QuatVector
1273
1274//==========================================================================================
1276Do_Data_Compression(int datasize)
1277{
1278return;
1279 //Find Min_Max
1280 float value_min=FLT_MAX;
1281 float value_max=-FLT_MAX;
1282 int count=datasize/sizeof(float);
1283 for (int i=0;i<count;i++) {
1284 float value=Data[i];
1285 if (_isnan(value)) value=0.0f;
1286 if (value>100000.0f) value=0.0f;
1287 if (value<-100000.0f) value=0.0f;
1288 Data[i]=value;
1289
1290 if (value_min > value) value_min = value;
1291 if (value_max < value) value_max = value;
1292 }
1293 ValueOffset=value_min;
1294 ValueScale=value_max-value_min;
1295 // Can't compress if the range is too high
1296 if (ValueScale>2000.0f) return;
1297 if (Type==ANIM_CHANNEL_Q/* && ValueScale>3.0f*/) return;
1298
1299 WWASSERT(!CompressedData);
1300 CompressedData=new unsigned short[count];
1301 float inv_scale=0.0f;
1302 if (ValueScale!=0.0f) {
1303 inv_scale=1.0f/ValueScale;
1304 }
1305 inv_scale*=65535.0f;
1306 for (i=0;i<count;++i) {
1307 float value=Data[i];
1308 value-=ValueOffset;
1309 value*=inv_scale;
1311 CompressedData[i]=unsigned short(ivalue);
1312
1313 float new_scale=ValueScale/65535.0f;
1314 float new_value=int(CompressedData[i]);
1315 float new_float = new_value*new_scale+ValueOffset;
1316// if (fabs(new_float-Data[i])>ValueScale/65536.0f) {
1317// int ii=0;
1318// }
1319
1320 }
1321
1322 delete[] Data;
1323 Data=NULL;
1324}
1325
1326
1327
1328// EOF - motchan.cpp
1329
#define NULL
Definition BaseType.h:92
void const char * value
#define WWASSERT
#define W3D_TIMECODED_BIT_MASK
Definition w3d_file.h:1490
#define W3D_TIMECODED_BINARY_MOVEMENT_FLAG
Definition w3d_file.h:1478
@ ANIM_CHANNEL_Q
Definition w3d_file.h:1419
#define MSGW3DNEWARRAY(MSG)
Definition always.h:108
unsigned long uint32
Definition bittype.h:46
float float32
Definition bittype.h:54
unsigned char uint8
Definition bittype.h:44
#define DEG_TO_RAD(x)
Definition wwmath.h:79
void Get_Vector(float32 frame, float *setvec)
Definition motchan.cpp:1226
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:940
Quaternion Get_QuatVector(float32 frame)
Definition motchan.cpp:1245
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:273
BitChannelClass(void)
Definition motchan.cpp:211
~BitChannelClass(void)
Definition motchan.cpp:234
uint32 Cur_Chunk_Length()
Definition chunkio.cpp:503
uint32 Seek(uint32 nbytes)
Definition chunkio.cpp:650
uint32 Read(void *buf, uint32 nbytes)
Definition chunkio.cpp:692
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:161
~MotionChannelClass(void)
Definition motchan.cpp:119
void Do_Data_Compression(int datasize)
Definition motchan.cpp:1276
MotionChannelClass(void)
Definition motchan.cpp:94
WWINLINE void Set(float a=0.0, float b=0.0, float c=0.0, float d=1.0)
Definition quat.h:73
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:754
int Get_Bit(int frame)
Definition motchan.cpp:803
Quaternion Get_QuatVector(float32 frame)
Definition motchan.cpp:482
void Get_Vector(float32 frame, float *setvec)
Definition motchan.cpp:428
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:386
static float Lerp(float a, float b, float lerp)
Definition wwmath.h:270
static WWINLINE int Float_To_Int_Floor(const float &f)
Definition wwmath.h:584
static float Sin(float val)
Definition wwmath.h:378
#define FILTER_TABLE_SIZE
Definition motchan.cpp:57
#define FILTER_TABLE_GEN_START
Definition motchan.cpp:58
#define FILTER_TABLE_GEN_SIZE
Definition motchan.cpp:59
#define PACKET_SIZE
Definition motchan.cpp:983
int q
Definition test1.cpp:94
void __cdecl Fast_Slerp(Quaternion &res, const Quaternion &p, const Quaternion &q, float alpha)
Definition quat.cpp:441
unsigned char filter
Definition vchannel.cpp:272