Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
hcanim.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/hcanim.cpp 3 6/29/01 6:41p Jani_p $ */
20/***********************************************************************************************
21 *** Confidential - Westwood Studios ***
22 ***********************************************************************************************
23 * *
24 * Project Name : Commando / G 3D Library *
25 * *
26 * $Archive:: /Commando/Code/ww3d2/hcanim.cpp $*
27 * *
28 * Author:: Greg_h *
29 * *
30 * $Modtime:: 6/27/01 7:50p $*
31 * *
32 * $Revision:: 3 $*
33 * *
34 *---------------------------------------------------------------------------------------------*
35 * Functions: *
36 * NodeMotionStruct::NodeMotionStruct -- constructor *
37 * NodeMotionStruct::~NodeMotionStruct -- destructor *
38 * HCompressedAnimClass::HCompressedAnimClass -- constructor *
39 * HCompressedAnimClass::~HCompressedAnimClass -- Destructor *
40 * HCompressedAnimClass::Free -- De-allocates all memory in use *
41 * HCompressedAnimClass::Load -- Loads hierarchy animation from a file *
42 * HCompressedAnimClass::read_channel -- Reads in a single channel of motion *
43 * HCompressedAnimClass::add_channel -- Adds a motion channel to the animation *
44 * HCompressedAnimClass::Get_Translation -- returns the translation vector for the given fram*
45 * HCompressedAnimClass::Get_Orientation -- returns a quaternion for the orientation of the p*
46 * HCompressedAnimClass::read_bit_channel -- read a bit channel from the file *
47 * HCompressedAnimClass::add_bit_channel -- install a bit channel into the animation *
48 * HCompressedAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
49 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
50
51
52#include "hcanim.h"
53#include "assetmgr.h"
54#include "htree.h"
55#include "motchan.h"
56#include "chunkio.h"
57#include "w3d_file.h"
58#include "wwdebug.h"
59#include <string.h>
60#include <nstrdup.h>
61
62
99
100/***********************************************************************************************
101 * NodeCompressedMotionStruct::NodeCompressedMotionStruct -- constructor *
102 * *
103 * INPUT: *
104 * *
105 * OUTPUT: *
106 * *
107 * WARNINGS: *
108 * *
109 * HISTORY: *
110 *=============================================================================================*/
112 Vis(NULL)
113{
114 vd.X = NULL;
115 vd.Y = NULL;
116 vd.Z = NULL;
117 vd.Q = NULL;
118}
119
120
121/***********************************************************************************************
122 * NodeCompressedMotionStruct::~NodeCompressedMotionStruct -- destructor *
123 * *
124 * INPUT: *
125 * *
126 * OUTPUT: *
127 * *
128 * WARNINGS: *
129 * *
130 * HISTORY: *
131 * 10/23/98 GTH : Created. *
132 * 02/02/00 JGA : Compressed *
133 *=============================================================================================*/
135{
136 // Needs to be changed to call the correct destructors
137
138 switch (Flavor) {
140 if (tc.X) delete tc.X;
141 if (tc.Y) delete tc.Y;
142 if (tc.Z) delete tc.Z;
143 if (tc.Q) delete tc.Q;
144 break;
146 if (ad.X) delete ad.X;
147 if (ad.Y) delete ad.Y;
148 if (ad.Z) delete ad.Z;
149 if (ad.Q) delete ad.Q;
150 break;
151 default:
152 WWASSERT(0); // unknown flavor
153 break;
154 }
155
156 if (Vis) delete Vis;
157
158} // ~NodeCompressedMotionStruct
159
160
161/***********************************************************************************************
162 * HCompressedAnimClass::HCompressedAnimClass -- constructor *
163 * *
164 * INPUT: *
165 * *
166 * OUTPUT: *
167 * *
168 * WARNINGS: *
169 * *
170 * HISTORY: *
171 * 08/11/1997 GH : Created. *
172 *=============================================================================================*/
174 NumFrames(0),
175 NumNodes(0),
176 Flavor(0),
177 FrameRate(0),
178 NodeMotion(NULL)
179{
180 memset(Name,0,W3D_NAME_LEN);
181 memset(HierarchyName,0,W3D_NAME_LEN);
182}
183
184
185/***********************************************************************************************
186 * HCompressedAnimClass::~HCompressedAnimClass -- Destructor *
187 * *
188 * INPUT: *
189 * *
190 * OUTPUT: *
191 * *
192 * WARNINGS: *
193 * *
194 * HISTORY: *
195 * 08/11/1997 GH : Created. *
196 *=============================================================================================*/
201
202
203/***********************************************************************************************
204 * HCompressedAnimClass::Free -- De-allocates all memory in use *
205 * *
206 * INPUT: *
207 * *
208 * OUTPUT: *
209 * *
210 * WARNINGS: *
211 * *
212 * HISTORY: *
213 * 08/11/1997 GH : Created. *
214 *=============================================================================================*/
215void HCompressedAnimClass::Free(void)
216{
217 if (NodeMotion != NULL) {
218 delete[] NodeMotion;
219 }
220}
221
222
223/***********************************************************************************************
224 * HCompressedAnimClass::Load -- Loads hierarchy animation from a file *
225 * *
226 * INPUT: *
227 * *
228 * OUTPUT: *
229 * *
230 * WARNINGS: *
231 * *
232 * HISTORY: *
233 * 08/11/1997 GH : Created. *
234 *=============================================================================================*/
236{
237 int i = 0;
238 /*
239 ** First make sure we release any memory in use
240 */
241 Free();
242
243 /*
244 ** Open the first chunk, it should be the animation header
245 */
246 if (!cload.Open_Chunk()) return LOAD_ERROR;
247
249 // ERROR: Expected Animation Header!
250 return LOAD_ERROR;
251 }
252
254 if (cload.Read(&aheader,sizeof(W3dAnimHeaderStruct)) != sizeof(W3dAnimHeaderStruct)) {
255 return LOAD_ERROR;
256 }
257
258 cload.Close_Chunk();
259
260 strcpy(Name,aheader.HierarchyName);
261 strcat(Name,".");
262 strcat(Name,aheader.Name);
263
264 // TSS chasing crash bug 05/26/99
265 WWASSERT(HierarchyName != NULL);
266 WWASSERT(aheader.HierarchyName != NULL);
267 WWASSERT(sizeof(HierarchyName) >= W3D_NAME_LEN);
268 strncpy(HierarchyName,aheader.HierarchyName,W3D_NAME_LEN);
269
270 HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
271 if (base_pose == NULL) {
272 goto Error;
273 }
274 NumNodes = base_pose->Num_Pivots();
275
276 NumFrames = aheader.NumFrames;
277 FrameRate = aheader.FrameRate;
278 Flavor = aheader.Flavor;
279
280 // Just for now
282
283 NodeMotion = W3DNEWARRAY NodeCompressedMotionStruct[ NumNodes ];
284 if (NodeMotion == NULL) {
285 goto Error;
286 }
287
288 // Initialize Flavor
289 for (i=0; i<NumNodes; i++) {
290 NodeMotion[i].SetFlavor(Flavor);
291 }
292
293 /*
294 ** Now, read in all of the other chunks (motion channels).
295 */
298 TimeCodedBitChannelClass * newbitchan;
299
300 while (cload.Open_Chunk()) {
301
302 switch (cload.Cur_Chunk_ID()) {
303
305
306 switch ( Flavor ) {
307
309
310 if (!read_channel(cload,&tc_chan)) {
311 goto Error;
312 }
313 if (tc_chan->Get_Pivot() < NumNodes) {
314 add_channel(tc_chan);
315 } else {
316 // PWG 12-14-98: we have only allocated space for NumNode pivots.
317 // If we have an index thats equal or higher than NumNode we are
318 // gonna trash memory. Boy will we trash memory.
319 // GTH 09-25-2000: print a warning and survive this error
320 delete tc_chan;
321 WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
322 }
323
324 break;
325
327 if (!read_channel(cload,&ad_chan)) {
328 goto Error;
329 }
330 if (ad_chan->Get_Pivot() < NumNodes) {
331 add_channel(ad_chan);
332 } else {
333 // PWG 12-14-98: we have only allocated space for NumNode pivots.
334 // If we have an index thats equal or higher than NumNode we are
335 // gonna trash memory. Boy will we trash memory.
336 // GTH 09-25-2000: print a warning and survive this error
337 delete ad_chan;
338 WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
339 }
340 break;
341 }
342 break;
343
345 if (!read_bit_channel(cload,&newbitchan)) {
346 goto Error;
347 }
348 if (newbitchan->Get_Pivot() < NumNodes) {
349 add_bit_channel(newbitchan);
350 } else {
351 // PWG 12-14-98: we have only allocated space for NumNode pivots.
352 // If we have an index thats equal or higher than NumNode we are
353 // gonna trash memory. Boy will we trash memory.
354 // GTH 09-25-2000: print a warning and survive this error
355 delete newbitchan;
356 WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
357 }
358
359 break;
360
361 default:
362 break;
363 }
364 cload.Close_Chunk();
365 }
366
367 return OK;
368
369Error:
370
371 Free();
372 return LOAD_ERROR;
373
374} // Load_W3D
375
376/***********************************************************************************************
377 * HCompressedAnimClass::read_channel -- Reads in a single channel of motion *
378 * *
379 * INPUT: *
380 * *
381 * OUTPUT: *
382 * *
383 * WARNINGS: *
384 * *
385 * HISTORY: *
386 * 08/11/1997 GH : Created. *
387 *=============================================================================================*/
388bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,TimeCodedMotionChannelClass * * newchan)
389{
391 bool result = (*newchan)->Load_W3D(cload);
392
393 return result;
394
395} // read_channel
396
397bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,AdaptiveDeltaMotionChannelClass * * newchan)
398{
399 *newchan = W3DNEW AdaptiveDeltaMotionChannelClass;
400 bool result = (*newchan)->Load_W3D(cload);
401
402 return result;
403
404} // read_channel
405
406
407/***********************************************************************************************
408 * HCompressedAnimClass::add_channel -- Adds a motion channel to the animation *
409 * *
410 * INPUT: *
411 * *
412 * OUTPUT: *
413 * *
414 * WARNINGS: *
415 * *
416 * HISTORY: *
417 * 08/11/1997 GH : Created. *
418 *=============================================================================================*/
419void HCompressedAnimClass::add_channel(TimeCodedMotionChannelClass * newchan)
420{
421 int idx = newchan->Get_Pivot();
422
423 switch (newchan->Get_Type())
424 {
425 case ANIM_CHANNEL_X:
426 NodeMotion[idx].tc.X = newchan;
427 break;
428
429 case ANIM_CHANNEL_Y:
430 NodeMotion[idx].tc.Y = newchan;
431 break;
432
433 case ANIM_CHANNEL_Z:
434 NodeMotion[idx].tc.Z = newchan;
435 break;
436
437 case ANIM_CHANNEL_Q:
438 NodeMotion[idx].tc.Q = newchan;
439 break;
440 }
441
442} // add_channel
443
444void HCompressedAnimClass::add_channel(AdaptiveDeltaMotionChannelClass * newchan)
445{
446 int idx = newchan->Get_Pivot();
447
448 switch (newchan->Get_Type())
449 {
450 case ANIM_CHANNEL_X:
451 NodeMotion[idx].ad.X = newchan;
452 break;
453
454 case ANIM_CHANNEL_Y:
455 NodeMotion[idx].ad.Y = newchan;
456 break;
457
458 case ANIM_CHANNEL_Z:
459 NodeMotion[idx].ad.Z = newchan;
460 break;
461
462 case ANIM_CHANNEL_Q:
463 NodeMotion[idx].ad.Q = newchan;
464 break;
465 }
466
467} // add_channel
468
469
470
471
472/***********************************************************************************************
473 * HCompressedAnimClass::read_bit_channel -- read a bit channel from the file *
474 * *
475 * INPUT: *
476 * *
477 * OUTPUT: *
478 * *
479 * WARNINGS: *
480 * *
481 * HISTORY: *
482 * 1/19/98 GTH : Created. *
483 *=============================================================================================*/
484bool HCompressedAnimClass::read_bit_channel(ChunkLoadClass & cload,TimeCodedBitChannelClass * * newchan)
485{
486 *newchan = W3DNEW TimeCodedBitChannelClass;
487 bool result = (*newchan)->Load_W3D(cload);
488
489 return result;
490
491} // read_bit_channel
492
493
494/***********************************************************************************************
495 * HCompressedAnimClass::add_bit_channel -- install a bit channel into the animation *
496 * *
497 * INPUT: *
498 * *
499 * OUTPUT: *
500 * *
501 * WARNINGS: *
502 * *
503 * HISTORY: *
504 * 1/19/98 GTH : Created. *
505 *=============================================================================================*/
506void HCompressedAnimClass::add_bit_channel(TimeCodedBitChannelClass * newchan)
507{
508 int idx = newchan->Get_Pivot();
509
510 switch (newchan->Get_Type())
511 {
512 case BIT_CHANNEL_VIS:
513 NodeMotion[idx].Vis = newchan;
514 break;
515 }
516}
517
518/***********************************************************************************************
519 * HCompressedAnimClass::Get_Translation -- returns the translation vector for the given frame *
520 * *
521 * INPUT: *
522 * *
523 * OUTPUT: *
524 * *
525 * WARNINGS: *
526 * *
527 * HISTORY: *
528 * 08/11/1997 GH : Created. *
529 *=============================================================================================*/
530void HCompressedAnimClass::Get_Translation( Vector3& trans, int pividx, float frame ) const
531{
532 struct NodeCompressedMotionStruct * motion = &NodeMotion[pividx];
533
534 trans=Vector3(0,0,0);
535
536 switch(Flavor) {
538 if (motion->tc.X) motion->tc.X->Get_Vector(frame, &(trans[0]));
539 if (motion->tc.Y) motion->tc.Y->Get_Vector(frame, &(trans[1]));
540 if (motion->tc.Z) motion->tc.Z->Get_Vector(frame, &(trans[2]));
541 break;
543 if (motion->ad.X) motion->ad.X->Get_Vector(frame, &(trans[0]));
544 if (motion->ad.Y) motion->ad.Y->Get_Vector(frame, &(trans[1]));
545 if (motion->ad.Z) motion->ad.Z->Get_Vector(frame, &(trans[2]));
546 break;
547 default:
548 WWASSERT(0); // unknown flavor
549 break;
550 }
551}
552
553/***********************************************************************************************
554 * HCompressedAnimClass::Get_Orientation -- returns a quaternion for the orientation of the *
555 * *
556 * INPUT: *
557 * *
558 * OUTPUT: *
559 * *
560 * WARNINGS: *
561 * *
562 * HISTORY: *
563 * 08/11/1997 GH : Created. *
564 *=============================================================================================*/
565void HCompressedAnimClass::Get_Orientation(Quaternion& q, int pividx,float frame) const
566{
567 switch(Flavor) {
569 if (NodeMotion[pividx].tc.Q) q = NodeMotion[pividx].tc.Q->Get_QuatVector(frame);
570 else q.Make_Identity();
571 break;
573 if (NodeMotion[pividx].ad.Q) q = NodeMotion[pividx].ad.Q->Get_QuatVector(frame);
574 else q.Make_Identity();
575 break;
576 default:
577 WWASSERT(0); // unknown flavor
578 break;
579 }
580} // Get_Orientation
581
582/***********************************************************************************************
583 * HCompressedAnimClass::Get_Transform -- returns the transform matrix for the given frame *
584 * *
585 * INPUT: *
586 * *
587 * OUTPUT: *
588 * *
589 * WARNINGS: *
590 * *
591 * HISTORY: *
592 * 08/11/1997 GH : Created. *
593 *=============================================================================================*/
594void HCompressedAnimClass::Get_Transform( Matrix3D& mtx, int pividx, float frame ) const
595{
596 struct NodeCompressedMotionStruct * motion = &NodeMotion[pividx];
597
598 switch(Flavor) {
600 if (NodeMotion[pividx].tc.Q) {
602 q = NodeMotion[pividx].tc.Q->Get_QuatVector(frame);
603 ::Build_Matrix3D(q,mtx);
604 }
605 else mtx.Make_Identity();
606 if (motion->tc.X) motion->tc.X->Get_Vector(frame, &(mtx[0][3]));
607 if (motion->tc.Y) motion->tc.Y->Get_Vector(frame, &(mtx[1][3]));
608 if (motion->tc.Z) motion->tc.Z->Get_Vector(frame, &(mtx[2][3]));
609 break;
611 if (NodeMotion[pividx].ad.Q) {
613 q = NodeMotion[pividx].ad.Q->Get_QuatVector(frame);
614 ::Build_Matrix3D(q,mtx);
615 }
616 else mtx.Make_Identity();
617
618 if (motion->ad.X) motion->ad.X->Get_Vector(frame, &(mtx[0][3]));
619 if (motion->ad.Y) motion->ad.Y->Get_Vector(frame, &(mtx[1][3]));
620 if (motion->ad.Z) motion->ad.Z->Get_Vector(frame, &(mtx[2][3]));
621 break;
622 default:
623 WWASSERT(0); // unknown flavor
624 break;
625 }
626}
627
628/***********************************************************************************************
629 * HCompressedAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
630 * *
631 * INPUT: *
632 * *
633 * OUTPUT: *
634 * *
635 * WARNINGS: *
636 * *
637 * HISTORY: *
638 * 1/19/98 GTH : Created. *
639 *=============================================================================================*/
640bool HCompressedAnimClass::Get_Visibility(int pividx,float frame)
641{
642
643 if (NodeMotion[pividx].Vis != NULL) {
644 return (NodeMotion[pividx].Vis->Get_Bit((int)frame) == 1);
645 }
646
647
648 // default to always visible...
649 return 1;
650}
651
652
653
654/***********************************************************************************************
655 * HAnimClass::Is_Node_Motion_Present -- return true if there is motion defined for this frame *
656 * *
657 * INPUT: *
658 * *
659 * OUTPUT: *
660 * *
661 * WARNINGS: *
662 * *
663 * HISTORY: *
664 * 3/23/99 EHC : Created. *
665 *=============================================================================================*/
667{
668 WWASSERT((pividx >= 0) && (pividx < NumNodes));
669
670 if (NodeMotion[pividx].vd.X != NULL) return true;
671 if (NodeMotion[pividx].vd.Y != NULL) return true;
672 if (NodeMotion[pividx].vd.Z != NULL) return true;
673 if (NodeMotion[pividx].vd.Q != NULL) return true;
674 if (NodeMotion[pividx].Vis != NULL) return true;
675
676 return false;
677}
678
680{
681 WWASSERT((pividx >= 0) && (pividx < NumNodes));
682 return NodeMotion[pividx].vd.X != NULL;
683}
684
686{
687 WWASSERT((pividx >= 0) && (pividx < NumNodes));
688 return NodeMotion[pividx].vd.Y != NULL;
689}
690
692{
693 WWASSERT((pividx >= 0) && (pividx < NumNodes));
694 return NodeMotion[pividx].vd.Z != NULL;
695}
696
698{
699 WWASSERT((pividx >= 0) && (pividx < NumNodes));
700 return NodeMotion[pividx].vd.Q != NULL;
701}
702
704{
705 WWASSERT((pividx >= 0) && (pividx < NumNodes));
706 return NodeMotion[pividx].Vis != NULL;
707}
708
709
710// eof - hcanim.cpp
#define NULL
Definition BaseType.h:92
#define WWASSERT
@ ANIM_FLAVOR_TIMECODED
Definition w3d_file.h:1437
@ ANIM_FLAVOR_ADAPTIVE_DELTA
Definition w3d_file.h:1438
#define W3D_NAME_LEN
Definition w3d_file.h:319
@ W3D_CHUNK_COMPRESSED_BIT_CHANNEL
Definition w3d_file.h:409
@ W3D_CHUNK_COMPRESSED_ANIMATION_HEADER
Definition w3d_file.h:407
@ W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL
Definition w3d_file.h:408
@ ANIM_CHANNEL_Y
Definition w3d_file.h:1414
@ ANIM_CHANNEL_Z
Definition w3d_file.h:1415
@ ANIM_CHANNEL_X
Definition w3d_file.h:1413
@ ANIM_CHANNEL_Q
Definition w3d_file.h:1419
@ BIT_CHANNEL_VIS
Definition w3d_file.h:1458
#define W3DNEWARRAY
Definition always.h:110
#define W3DNEW
Definition always.h:109
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:940
bool Close_Chunk()
Definition chunkio.cpp:448
uint32 Cur_Chunk_ID()
Definition chunkio.cpp:484
uint32 Read(void *buf, uint32 nbytes)
Definition chunkio.cpp:692
bool Open_Chunk()
Definition chunkio.cpp:412
bool Has_X_Translation(int pividx)
Definition hcanim.cpp:679
bool Has_Y_Translation(int pividx)
Definition hcanim.cpp:685
bool Has_Visibility(int pividx)
Definition hcanim.cpp:703
bool Get_Visibility(int pividx, float frame)
Definition hcanim.cpp:640
void Get_Transform(Matrix3D &transform, int pividx, float frame) const
Definition hcanim.cpp:594
bool Has_Z_Translation(int pividx)
Definition hcanim.cpp:691
void Get_Translation(Vector3 &translation, int pividx, float frame) const
Definition hcanim.cpp:530
bool Is_Node_Motion_Present(int pividx)
Definition hcanim.cpp:666
bool Has_Rotation(int pividx)
Definition hcanim.cpp:697
~HCompressedAnimClass(void)
Definition hcanim.cpp:197
void Get_Orientation(Quaternion &orientation, int pividx, float frame) const
Definition hcanim.cpp:565
int Load_W3D(ChunkLoadClass &cload)
Definition hcanim.cpp:235
WWINLINE int Num_Pivots(void) const
Definition htree.h:93
WWINLINE void Make_Identity(void)
Definition matrix3d.h:650
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:754
void Get_Vector(float32 frame, float *setvec)
Definition motchan.cpp:428
bool Load_W3D(ChunkLoadClass &cload)
Definition motchan.cpp:386
static WW3DAssetManager * Get_Instance(void)
Definition assetmgr.h:205
virtual HTreeClass * Get_HTree(const char *name)
int q
Definition test1.cpp:94
Matrix3D & Build_Matrix3D(const Quaternion &q, Matrix3D &out)
Definition quat.h:208
TimeCodedMotionChannelClass * Z
Definition hcanim.cpp:76
void SetFlavor(int flavor)
Definition hcanim.cpp:68
struct NodeCompressedMotionStruct::@251120225114162023026320156143164261166107265171::@275165275207377012347063022205303177170156130340 ad
TimeCodedMotionChannelClass * Q
Definition hcanim.cpp:77
TimeCodedMotionChannelClass * Y
Definition hcanim.cpp:75
struct NodeCompressedMotionStruct::@251120225114162023026320156143164261166107265171::@211370060311145330016175051277266071252065320323 vd
struct NodeCompressedMotionStruct::@251120225114162023026320156143164261166107265171::@141172220036133323143076343377314335114247053033 tc
TimeCodedMotionChannelClass * X
Definition hcanim.cpp:74
TimeCodedBitChannelClass * Vis
Definition hcanim.cpp:97
char Name[W3D_NAME_LEN]
Definition w3d_file.h:1403
char HierarchyName[W3D_NAME_LEN]
Definition w3d_file.h:1404
#define WWDEBUG_SAY(x)
Definition wwdebug.h:114