Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
htree.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/htree.cpp 14 10/01/01 6:07p Patrick $ */
20/***********************************************************************************************
21 *** Confidential - Westwood Studios ***
22 ***********************************************************************************************
23 * *
24 * Project Name : Commando / G 3D Library *
25 * *
26 * $Archive:: /Commando/Code/ww3d2/htree.cpp $*
27 * *
28 * Author:: Greg_h *
29 * *
30 * $Modtime:: 10/01/01 6:06p $*
31 * *
32 * $Revision:: 14 $*
33 * *
34 *---------------------------------------------------------------------------------------------*
35 * Functions: *
36 * HTreeClass::HTreeClass -- constructor *
37 * HTreeClass::~HTreeClass -- destructor *
38 * HTreeClass::Load -- loads a hierarchy tree from a file *
39 * HTreeClass::read_pivots -- reads the pivots out of a file *
40 * HTreeClass::Free -- de-allocate all memory in use *
41 * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
42 * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
43 * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
44 * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
45 * HTreeClass::Get_Transform -- returns the transformation for the desired pivot *
46 * HTreeClass::Find_Bone -- Find a bone by name *
47 * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
48 * HTreeClass::Update_Parent_Need_Bits -- all "needed" children force their parents to be nee*
49 * HTreeClass::HTreeClass -- copy constructor *
50 * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
51 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
52
53
54#include "htree.h"
55#include "hanim.h"
56#include "hcanim.h"
57#include <string.h>
58#include <assert.h>
59#include "wwmath.h"
60#include "chunkio.h"
61#include "w3d_file.h"
62#include "wwmemlog.h"
63#include "hrawanim.h"
64#include "motchan.h"
65
66/***********************************************************************************************
67 * HTreeClass::HTreeClass -- constructor *
68 * *
69 * INPUT: *
70 * *
71 * OUTPUT: *
72 * *
73 * WARNINGS: *
74 * *
75 * HISTORY: *
76 * 08/11/1997 GH : Created. *
77 *=============================================================================================*/
79 NumPivots(0),
80 Pivot(NULL),
81 ScaleFactor(1.0f)
82{
83}
84
86{
87 Free ();
88
89 NumPivots = 1;
90 Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
91
92 Pivot[0].Index = 0;
93 Pivot[0].Parent = NULL;
94 Pivot[0].BaseTransform.Make_Identity();
95 Pivot[0].Transform.Make_Identity();
96 Pivot[0].IsVisible = true;
97 strcpy(Pivot[0].Name,"RootTransform");
98 //::strcpy (Name, "Default");
99 Name[0] = 0;
100 return ;
101
102
103
104}
105
106/***********************************************************************************************
107 * HTreeClass::~HTreeClass -- destructor *
108 * *
109 * INPUT: *
110 * *
111 * OUTPUT: *
112 * *
113 * WARNINGS: *
114 * *
115 * HISTORY: *
116 * 08/11/1997 GH : Created. *
117 *=============================================================================================*/
119{
120 Free();
121
122
123
124}
125
126
127/***********************************************************************************************
128 * HTreeClass::HTreeClass -- copy constructor *
129 * *
130 * INPUT: *
131 * *
132 * OUTPUT: *
133 * *
134 * WARNINGS: *
135 * *
136 * HISTORY: *
137 * 3/4/98 GTH : Created. *
138 *=============================================================================================*/
140 NumPivots(0),
141 Pivot(NULL),
142 ScaleFactor(1.0f)
143{
144 memcpy(&Name,&src.Name,sizeof(Name));
145
146 NumPivots = src.NumPivots;
147 if (NumPivots > 0) {
148 Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
149 }
150
151 for (int pi = 0; pi < NumPivots; pi++) {
152 Pivot[pi] = src.Pivot[pi];
153
154 if (src.Pivot[pi].Parent != NULL) {
155 Pivot[pi].Parent = &(Pivot[src.Pivot[pi].Parent->Index]);
156 } else {
157 Pivot[pi].Parent = NULL;
158 }
159 }
160
161 ScaleFactor = src.ScaleFactor;
162}
163
164/***********************************************************************************************
165 * HTreeClass::Load -- loads a hierarchy tree from a file *
166 * *
167 * INPUT: *
168 * *
169 * OUTPUT: *
170 * *
171 * WARNINGS: *
172 * *
173 * HISTORY: *
174 * 08/11/1997 GH : Created. *
175 *=============================================================================================*/
177{
178 Free();
179
180 /*
181 ** Read the first chunk, it should be the hierarchy header
182 */
183 if (!cload.Open_Chunk()) return LOAD_ERROR;
184
186 // ERROR: Expected Hierarchy Header
187 return LOAD_ERROR;
188 }
189
190 W3dHierarchyStruct header;
191 if (cload.Read(&header,sizeof(W3dHierarchyStruct)) != sizeof(W3dHierarchyStruct)) {
192 return LOAD_ERROR;
193 }
194
195 cload.Close_Chunk();
196
197 /*
198 ** Check the version, if < 3.0 add a root node for everything
199 ** to attach to. The load_pivots function will also have to be
200 ** notified of this.
201 */
202 bool pre30 = false;
203 if (header.Version < W3D_MAKE_VERSION(3,0)) {
204 header.NumPivots ++;
205 pre30 = true;
206 }
207
208 /*
209 ** Allocate the array of pivots
210 */
211 memcpy(Name,header.Name,W3D_NAME_LEN);
212 NumPivots = header.NumPivots;
213 if (NumPivots > 0) {
214 Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
215 }
216
217 /*
218 ** Now, read in all of the other chunks for this hierarchy.
219 */
220
221 while (cload.Open_Chunk()) {
222
223 switch (cload.Cur_Chunk_ID()) {
224
225 case W3D_CHUNK_PIVOTS:
226 if (!read_pivots(cload,pre30)) {
227 goto Error;
228 }
229 break;
230
231 default:
232 // ERROR: expected W3D_CHUNK_PIVOTS!
233 break;
234 }
235 cload.Close_Chunk();
236 }
237
238 return OK;
239
240Error:
241
242 Free();
243 return LOAD_ERROR;
244}
245
246
247/***********************************************************************************************
248 * HTreeClass::read_pivots -- reads the pivots out of a file *
249 * *
250 * INPUT: *
251 * *
252 * OUTPUT: *
253 * *
254 * WARNINGS: *
255 * *
256 * HISTORY: *
257 * 08/11/1997 GH : Created. *
258 *=============================================================================================*/
259bool HTreeClass::read_pivots(ChunkLoadClass & cload,bool pre30)
260{
261 W3dPivotStruct piv;
262 Matrix3D mtx;
263
264 int first_piv = 0;
265
266 /*
267 ** At (w3d file format) version 3.0, I added a node for the root. Pre-3.0 htrees didn't have
268 ** this so we just put one in.
269 */
270 if (pre30) {
271 Pivot[0].Index = 0;
272 Pivot[0].Parent = NULL;
273 Pivot[0].BaseTransform.Make_Identity();
274 Pivot[0].Transform.Make_Identity();
275 Pivot[0].IsVisible = true;
276 strcpy(Pivot[0].Name,"RootTransform");
277 first_piv++;
278 }
279
280 for (int pidx=first_piv; pidx < NumPivots; pidx++) {
281
282 if (cload.Read(&piv,sizeof(W3dPivotStruct)) != sizeof(W3dPivotStruct)) {
283 return false;
284 }
285
286 memcpy(Pivot[pidx].Name,piv.Name,W3D_NAME_LEN);
287 Pivot[pidx].Index = pidx;
288
289 Pivot[pidx].BaseTransform.Make_Identity();
290 Pivot[pidx].BaseTransform.Translate(Vector3(piv.Translation.X,piv.Translation.Y,piv.Translation.Z));
291
292#ifdef ALLOW_TEMPORARIES
293 Pivot[pidx].BaseTransform =
294 Pivot[pidx].BaseTransform *
296 Quaternion(
297 piv.Rotation.Q[0],
298 piv.Rotation.Q[1],
299 piv.Rotation.Q[2],
300 piv.Rotation.Q[3]
301 ),
302 mtx
303 );
304#else
305 Pivot[pidx].BaseTransform.postMul(
307 Quaternion(
308 piv.Rotation.Q[0],
309 piv.Rotation.Q[1],
310 piv.Rotation.Q[2],
311 piv.Rotation.Q[3]
312 ),
313 mtx
314 )
315 );
316#endif
317
318 /*
319 ** At version 3.0 a root node was added, this "fixes up" pre-3.0 files
320 ** to have that root node
321 */
322 if (pre30) {
323 piv.ParentIdx += 1;
324 }
325
326 /*
327 ** Set the parent pointer. The first pivot will have a parent index
328 ** of -1 (in post-3.0 files) so set its parent to NULL.
329 */
330 if (piv.ParentIdx == -1) {
331 Pivot[pidx].Parent = NULL;
332 assert(pidx == 0);
333 } else {
334 Pivot[pidx].Parent = &(Pivot[piv.ParentIdx]);
335 }
336
337 }
338
339 Pivot[0].Transform.Make_Identity();
340 Pivot[0].IsVisible = true;
341
342 return true;
343}
344
345
346/***********************************************************************************************
347 * HTreeClass::Free -- de-allocate all memory in use *
348 * *
349 * INPUT: *
350 * *
351 * OUTPUT: *
352 * *
353 * WARNINGS: *
354 * *
355 * HISTORY: *
356 * 08/11/1997 GH : Created. *
357 *=============================================================================================*/
358void HTreeClass::Free(void)
359{
360 if (Pivot != NULL) {
361 delete[] Pivot;
362 Pivot = NULL;
363 }
364 NumPivots = 0;
365
366 // Also clean up other members:
367 ScaleFactor = 1.0f;
368}
369
370
371/***********************************************************************************************
372 * HTreeClass::Simple_Evaluate_Pivot -- Returns the transform of a pivot at the given frame. *
373 * *
374 * INPUT: *
375 * *
376 * OUTPUT: *
377 * *
378 * WARNINGS: *
379 * *
380 * HISTORY: *
381 * 04/13/2000 PDS : Created. *
382 *=============================================================================================*/
384(
385 HAnimClass * motion,
386 int pivot_index,
387 float frame,
388 const Matrix3D & obj_tm,
389 Matrix3D * end_tm
390) const
391{
392 bool retval = false;
393 end_tm->Make_Identity ();
394
395 if ( motion != NULL &&
396 end_tm != NULL &&
397 pivot_index >= 0 &&
398 pivot_index < NumPivots)
399 {
400 //
401 // Loop over the hierarchy of pivots that this pivot is
402 // attached to and transform each.
403 //
404 for ( PivotClass *pivot = &Pivot[pivot_index];
405 pivot != NULL && pivot->Parent != NULL;
406 pivot = pivot->Parent)
407 {
408 //
409 // Build a matrix that represents the animation for this pivot
410 //
411
412 Matrix3D anim_tm;
413 motion->Get_Transform(anim_tm, pivot->Index, frame);
414
415// Quaternion q;
416// motion->Get_Orientation (q, pivot->Index, frame);
417// Matrix3D anim_tm = ::Build_Matrix3D(q);
418
419 Vector3 trans;
420 anim_tm.Get_Translation(&trans);
421 anim_tm.Set_Translation(trans * ScaleFactor);
422
423 //
424 // Transform the animation transform by the 'relative-to-parent' transform.
425 //
426 Matrix3D curr_tm;
427 Matrix3D::Multiply(pivot->BaseTransform, anim_tm, &curr_tm);
428
429 //
430 // Transform the return value by this transform
431 //
432#ifdef ALLOW_TEMPORARIES
433 Matrix3D::Multiply (curr_tm, *end_tm, end_tm);
434#else
435 end_tm->preMul(curr_tm);
436#endif
437 }
438
439 //
440 // Transform the return value by the object's transform
441 //
442#ifdef ALLOW_TEMPORARIES
443 Matrix3D::Multiply (obj_tm, *end_tm, end_tm);
444#else
445 end_tm->preMul(obj_tm);
446#endif
447
448 // Success!
449 retval = true;
450 }
451
452 return retval;
453}
454
455
456
457/***********************************************************************************************
458 * HTreeClass::Simple_Evaluate_Pivot -- Returns the transform of a pivot at the given frame. *
459 * *
460 * INPUT: *
461 * *
462 * OUTPUT: *
463 * *
464 * WARNINGS: *
465 * *
466 * HISTORY: *
467 * 04/13/2000 PDS : Created. *
468 *=============================================================================================*/
470(
471 int pivot_index,
472 const Matrix3D & obj_tm,
473 Matrix3D * end_tm
474) const
475{
476 bool retval = false;
477 end_tm->Make_Identity ();
478
479 if ( end_tm != NULL &&
480 pivot_index >= 0 &&
481 pivot_index < NumPivots)
482 {
483 //
484 // Loop over the hierarchy of pivots that this pivot is
485 // attached to and transform each.
486 //
487 for ( PivotClass *pivot = &Pivot[pivot_index];
488 pivot != NULL && pivot->Parent != NULL;
489 pivot = pivot->Parent)
490 {
491 //
492 // Build a matrix that represents the animation for this pivot
493 //
494 Matrix3D anim_tm (1);
495
496 //
497 // Transform the animation transform by the 'relative-to-parent' transform.
498 //
499 Matrix3D curr_tm;
500 Matrix3D::Multiply (pivot->BaseTransform, anim_tm, &curr_tm);
501
502 //
503 // Transform the return value by this transform
504 //
505 Matrix3D::Multiply (curr_tm, *end_tm, end_tm);
506 }
507
508 //
509 // Transform the return value by the object's transform
510 //
511 Matrix3D::Multiply (obj_tm, *end_tm, end_tm);
512 retval = true;
513 }
514
515 return retval;
516}
517
518
519/***********************************************************************************************
520 * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
521 * *
522 * INPUT: *
523 * *
524 * OUTPUT: *
525 * *
526 * WARNINGS: *
527 * *
528 * HISTORY: *
529 * 08/11/1997 GH : Created. *
530 *=============================================================================================*/
532{
533 PivotClass *pivot;
534
535 Pivot[0].Transform = root;
536 Pivot[0].IsVisible = true;
537
538 for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
539
540 pivot = &Pivot[piv_idx];
541
542 assert(pivot->Parent != NULL);
543 Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
544 pivot->IsVisible = 1;
545
546 if (pivot->Is_Captured()) pivot->Capture_Update();
547 }
548}
549
550/***********************************************************************************************
551 * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
552 * *
553 * INPUT: *
554 * *
555 * OUTPUT: *
556 * *
557 * WARNINGS: *
558 * *
559 * HISTORY: *
560 * 08/11/1997 GH : Created. *
561 *=============================================================================================*/
562void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float frame)
563{
564 PivotClass *pivot;
565 Matrix3D mtx;
566
567 Pivot[0].Transform = root;
568 Pivot[0].IsVisible = true;
569
570 int num_anim_pivots = motion->Get_Num_Pivots ();
571
572 for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
573 pivot = &Pivot[piv_idx];
574
575 // base pose
576 assert(pivot->Parent != NULL);
577 Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
578
579 // Don't update this pivot if the HTree doesn't have animation data for it...
580 if (piv_idx < num_anim_pivots) {
581
582 // animation
583 Vector3 trans;
584 motion->Get_Translation(trans,piv_idx,frame);
585 pivot->Transform.Translate(trans * ScaleFactor);
586
588 motion->Get_Orientation(q,piv_idx,frame);
589 ::Build_Matrix3D(q,mtx);
590
591#ifdef ALLOW_TEMPORARIES
592 pivot->Transform = pivot->Transform * mtx;
593#else
594 pivot->Transform.postMul(mtx);
595#endif
596
597 // visibility
598 pivot->IsVisible = motion->Get_Visibility(piv_idx,frame);
599 }
600
601 if (pivot->Is_Captured())
602 {
603 pivot->Capture_Update();
604 pivot->IsVisible = true;
605 }
606 }
607}
608
609/*Customized version of the above which excludes interpolation and assumes HRawAnimClass
610For use by 'Generals' -MW*/
611void HTreeClass::Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame)
612{
613 PivotClass *pivot,*endpivot,*lastAnimPivot;
614
615 Pivot[0].Transform = root;
616 Pivot[0].IsVisible = true;
617
618
619 int num_anim_pivots = motion->Get_Num_Pivots ();
620
621 //Get integer frame
622 int iframe=WWMath::Float_To_Long(frame);
623 if (iframe >= motion->Get_Num_Frames())
624 iframe = 0;
625
626 Vector3 trans;
628 Matrix3D mtx;
629
630 struct NodeMotionStruct * nodeMotion = ((HRawAnimClass*)motion)->Get_Node_Motion_Array();
631 nodeMotion += 1; //skip the root node
632
633 pivot = &Pivot[1];
634 endpivot=pivot+(NumPivots-1);
635 lastAnimPivot = &Pivot[num_anim_pivots];
636
637 for (int piv_idx=1; pivot < endpivot; pivot++,nodeMotion++) {
638
639 // base pose
640 assert(pivot->Parent != NULL);
641 Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
642
643 // Don't update this pivot if the HTree doesn't have animation data for it...
644 if (pivot < lastAnimPivot)
645 {
646
647 // animation
648 trans.Set(0.0f,0.0f,0.0f);
649 Matrix3D *xform=&pivot->Transform;
650
651 if (nodeMotion->X != NULL)
652 nodeMotion->X->Get_Vector(iframe,&(trans[0]));
653 if (nodeMotion->Y != NULL)
654 nodeMotion->Y->Get_Vector(iframe,&(trans[1]));
655 if (nodeMotion->Z != NULL)
656 nodeMotion->Z->Get_Vector(iframe,&(trans[2]));
657
658 if (ScaleFactor == 1.0f)
659 xform->Translate(trans);
660 else
661 xform->Translate(trans*ScaleFactor);
662
663 if (nodeMotion->Q != NULL)
664 { nodeMotion->Q->Get_Vector_As_Quat(iframe, q);
665#ifdef ALLOW_TEMPORARIES
666 *xform = *xform * ::Build_Matrix3D(q,mtx);
667#else
668 xform->postMul(::Build_Matrix3D(q,mtx));
669#endif
670 }
671
672 // visibility
673 if (nodeMotion->Vis != NULL)
674 pivot->IsVisible=(nodeMotion->Vis->Get_Bit(iframe) == 1);
675 else
676 pivot->IsVisible=1;
677 }
678
679 if (pivot->Is_Captured())
680 {
681 pivot->Capture_Update();
682 pivot->IsVisible = true;
683 }
684 }
685}
686
687
688/***********************************************************************************************
689 * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
690 * *
691 * INPUT: *
692 * *
693 * OUTPUT: *
694 * *
695 * WARNINGS: *
696 * *
697 * HISTORY: *
698 * 3/4/98 GTH : Created. *
699 *=============================================================================================*/
701(
702 const Matrix3D & root,
703 HAnimClass * motion0,
704 float frame0,
705 HAnimClass * motion1,
706 float frame1,
707 float percentage // 0.0 = motion0. 1.0 = motion1
708)
709{
710 PivotClass *pivot;
711 Matrix3D mtx;
712
713 Pivot[0].Transform = root;
714 Pivot[0].IsVisible = true;
715
716 int num_anim_pivots = MIN( motion0->Get_Num_Pivots (), motion1->Get_Num_Pivots () );
717
718 for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
719
720 pivot = &Pivot[piv_idx];
721
722 assert(pivot->Parent != NULL);
724
725 if (piv_idx < num_anim_pivots) {
726 // interpolated translation
727 Vector3 trans0;
728 motion0->Get_Translation(trans0,piv_idx,frame0);
729 Vector3 trans1;
730 motion1->Get_Translation(trans1,piv_idx,frame1);
731 Vector3 lerped = (1.0 - percentage) * trans0 + (percentage) * trans1;
732 pivot->Transform.Translate(lerped * ScaleFactor);
733
734 // interpolated rotation
735 Quaternion q0;
736 motion0->Get_Orientation(q0,piv_idx,frame0);
737 Quaternion q1;
738 motion1->Get_Orientation(q1,piv_idx,frame1);
740 Fast_Slerp(q,q0,q1,percentage);
741#ifdef ALLOW_TEMPORARIES
742 pivot->Transform = pivot->Transform * Build_Matrix3D(q);
743#else
744 pivot->Transform.postMul(Build_Matrix3D(q,mtx));
745#endif
746
747 pivot->IsVisible = (motion0->Get_Visibility(piv_idx,frame0) || motion1->Get_Visibility(piv_idx,frame1));
748 }
749
750 if (pivot->Is_Captured())
751 {
752 pivot->Capture_Update();
753 pivot->IsVisible = true;
754 }
755 }
756}
757
758
759
760/***********************************************************************************************
761 * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
762 * *
763 * INPUT: *
764 * *
765 * OUTPUT: *
766 * *
767 * WARNINGS: *
768 * *
769 * HISTORY: *
770 * 3/4/98 GTH : Created. *
771 *=============================================================================================*/
773(
774 const Matrix3D & root,
775 HAnimComboClass *anim
776)
777{
778 PivotClass *pivot;
779 Matrix3D mtx;
780
781 Pivot[0].Transform = root;
782 Pivot[0].IsVisible = true;
783
784 int num_anim_pivots = 100000;
785 for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
786 num_anim_pivots = MIN( num_anim_pivots, anim->Peek_Motion( anim_num )->Get_Num_Pivots() );
787 }
788 if ( num_anim_pivots == 100000 ) {
789 num_anim_pivots = 0;
790 }
791
792 for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
793
794 pivot = &Pivot[piv_idx];
795 assert(pivot->Parent != NULL);
797
798 if (piv_idx < num_anim_pivots) {
799
800#define ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
801
802 Vector3 trans(0,0,0);
803 Quaternion q0;
804 Quaternion q1;
805#ifndef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
806 float last_weight = 0;
807#endif
808 float weight_total = 0;
809 int wcount = 0;
810
811 for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
812
813 HAnimClass *motion = anim->Get_Motion( anim_num );
814
815 if ( motion != NULL ) {
816
817 float frame_num = anim->Get_Frame( anim_num );
818
819 PivotMapClass * pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
820
821 //float *pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
822
823 float weight = anim->Get_Weight( anim_num );
824
825 if ( pivot_map != NULL ) {
826 weight *= (*pivot_map)[piv_idx];
827 // GREG - Pivot maps are ref counted so shouldn't we
828 // release the rivot map here?
829 pivot_map->Release_Ref();
830 }
831
832 if ( weight != 0.0 ) {
833
834 wcount++;
835 Vector3 temp_trans;
836 motion->Get_Translation( temp_trans, piv_idx, frame_num );
837 trans += weight * ScaleFactor * temp_trans;
838 weight_total += weight;
839
840#ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
841 motion->Get_Orientation(q1,piv_idx, frame_num );
842 if ( wcount == 1 ) {
843 q0 = q1;
844 } else {
845 Fast_Slerp(q0, q0, q1, weight / weight_total );
846 }
847#else
848 q0 = q1;
849 motion->Get_Orientation(q1, piv_idx, frame_num );
850 last_weight = weight;
851#endif
852 }
853
854 motion->Release_Ref();
855
856 }
857 }
858
859#ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
860
861 if (weight_total != 0.0f ) {
862 // SKB: Removed assert because I have a case where I don't want normalization.
863 // One anim moves X, the other moves Y. Assert was just in to warn programmers.
864// WWASSERT(WWMath::Fabs( weight_total - 1.0 ) < WWMATH_EPSILON);
865
866 pivot->Transform.Translate(trans);
867#ifdef ALLOW_TEMPORARIES
868 pivot->Transform = pivot->Transform * Build_Matrix3D(q0);
869#else
870 pivot->Transform.postMul(Build_Matrix3D(q0,mtx));
871#endif
872 }
873#else
874 if (( weight_total != 0.0f ) && (wcount >= 2)) {
875
876 pivot->Transform.Translate( trans / weight_total );
877 Quaternion q = Slerp_( q0, q1, last_weight / weight_total );
878 pivot->Transform = pivot->Transform * Build_Matrix3D(q);
879
880 } else if (weight_total != 0.0f) {
881
882 pivot->Transform.Translate( trans / weight_total );
883 pivot->Transform = pivot->Transform * Build_Matrix3D(q1);
884 }
885#endif
886
887 pivot->IsVisible = false;
888
889 for ( anim_num = 0; (anim_num < anim->Get_Num_Anims()) && (!pivot->IsVisible); anim_num++ ) {
890 HAnimClass *motion = anim->Get_Motion( anim_num );
891 if ( motion != NULL ) {
892 float frame_num = anim->Get_Frame( anim_num );
893
894 pivot->IsVisible |= motion->Get_Visibility(piv_idx,frame_num);
895
896 motion->Release_Ref();
897 }
898 }
899 }
900
901 if (pivot->Is_Captured())
902 {
903 pivot->Capture_Update();
904 pivot->IsVisible = true;
905 }
906 }
907}
908
909
910/***********************************************************************************************
911 * HTreeClass::Find_Bone -- Find a bone by name *
912 * *
913 * INPUT: *
914 * *
915 * OUTPUT: *
916 * *
917 * WARNINGS: *
918 * *
919 * HISTORY: *
920 * 11/4/97 GTH : Created. *
921 *=============================================================================================*/
922int HTreeClass::Get_Bone_Index(const char * name) const
923{
924 for (int i=0; i < NumPivots; i++) {
925 if (stricmp(Pivot[i].Name,name) == 0) {
926 return i;
927 }
928 }
929 return 0;
930}
931
932
933/***********************************************************************************************
934 * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
935 * *
936 * INPUT: *
937 * *
938 * OUTPUT: *
939 * *
940 * WARNINGS: *
941 * *
942 * HISTORY: *
943 * 11/4/97 GTH : Created. *
944 *=============================================================================================*/
945const char * HTreeClass::Get_Bone_Name(int boneidx) const
946{
947 assert(boneidx >= 0);
948 assert(boneidx < NumPivots);
949
950 return Pivot[boneidx].Name;
951}
952
953
954/***********************************************************************************************
955 * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
956 * *
957 * INPUT: *
958 * boneidx - the bone you are interested in *
959 * *
960 * OUTPUT: *
961 * the index of that bone's parent *
962 * *
963 * WARNINGS: *
964 * *
965 * HISTORY: *
966 * 4/12/2000 gth : Created. *
967 *=============================================================================================*/
968int HTreeClass::Get_Parent_Index(int boneidx) const
969{
970 assert(boneidx >= 0);
971 assert(boneidx < NumPivots);
972
973 if (Pivot[boneidx].Parent != NULL) {
974 return Pivot[boneidx].Parent->Index;
975 } else {
976 return 0;
977 }
978}
979
980
981// Scale this HTree by a constant factor:
982void HTreeClass::Scale(float factor)
983{
984 if (factor == 1.0f) return;
985
986 // Scale pivot translations
987 for (int i = 0; i < NumPivots; i++) {
988 Matrix3D &pivot_transform = Pivot[i].BaseTransform;
989 Vector3 pivot_translation;
990 pivot_transform.Get_Translation(&pivot_translation);
991 pivot_translation *= factor;
992 pivot_transform.Set_Translation(pivot_translation);
993 }
994
995 // Set state used later to scale animations:
996 ScaleFactor *= factor;
997}
998
999
1000
1001void HTreeClass::Capture_Bone(int boneindex)
1002{
1003 assert(boneindex >= 0);
1004 assert(boneindex < NumPivots);
1005#ifdef LAZY_CAP_MTX_ALLOC
1006 if (Pivot[boneindex].CapTransformPtr == NULL)
1007 {
1008 Pivot[boneindex].CapTransformPtr = MSGW3DNEW("PivotClassCaptureBoneMtx") DynamicMatrix3D;
1009 Pivot[boneindex].CapTransformPtr->Mat.Make_Identity();
1010 }
1011#else
1012 Pivot[boneindex].IsCaptured = true;
1013#endif
1014}
1015
1016void HTreeClass::Release_Bone(int boneindex)
1017{
1018 assert(boneindex >= 0);
1019 assert(boneindex < NumPivots);
1020#ifdef LAZY_CAP_MTX_ALLOC
1021 if (Pivot[boneindex].CapTransformPtr)
1022 {
1023 delete Pivot[boneindex].CapTransformPtr;
1024 Pivot[boneindex].CapTransformPtr = NULL;
1025 }
1026#else
1027 Pivot[boneindex].IsCaptured = false;
1028#endif
1029}
1030
1031bool HTreeClass::Is_Bone_Captured(int boneindex) const
1032{
1033 assert(boneindex >= 0);
1034 assert(boneindex < NumPivots);
1035 return Pivot[boneindex].Is_Captured();
1036}
1037
1038void HTreeClass::Control_Bone(int boneindex,const Matrix3D & relative_tm,bool world_space_translation)
1039{
1040 assert(boneindex >= 0);
1041 assert(boneindex < NumPivots);
1042 assert(Pivot[boneindex].Is_Captured());
1043
1044#ifdef LAZY_CAP_MTX_ALLOC
1045 if (Pivot[boneindex].CapTransformPtr == NULL)
1046 return;
1047 Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
1048 Pivot[boneindex].CapTransformPtr->Mat = relative_tm;
1049#else
1050 Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
1051 Pivot[boneindex].CapTransform = relative_tm;
1052#endif
1053}
1054
1055void HTreeClass::Get_Bone_Control(int boneindex, Matrix3D & relative_tm) const
1056{
1057 assert(boneindex >= 0);
1058 assert(boneindex < NumPivots);
1059
1060 //
1061 // Return the bone's control transform to the caller
1062 //
1063 if (Pivot[boneindex].IsCaptured) {
1064 relative_tm = Pivot[boneindex].CapTransform;
1065 } else {
1066 relative_tm.Make_Identity ();
1067 }
1068
1069 return ;
1070}
1071
1073{
1074 // This is a specific list of pivot names used in the avatar meshes that we need to special case for scaling
1075 // The reason is due to the fact that we want to scale the avatar's bone structure with differing amount for
1076 // each axis, and with the T-pos of the avatar skeleton, undesirable results are caused due to the arms and hands
1077 // being stretched out on the Y-axis instead of the Z-axis like the rest of the bodies. Hence, the list of pivots
1078 // below are ones that I will special case and scale them based on the Z-axis scaling factor instead of the Y-axis
1079 // scaling factor.
1080 char * flip_list[] = { " RIGHTFOREARM", " RIGHTHAND", " LEFTFOREARM", " LEFTHAND", "RIGHTINDEX", "RIGHTFINGERS", "RIGHTTHUMB", "LEFTINDEX", "LEFTFINGERS", "LEFTTHUMB", 0 };
1081
1082 // Clone the new tree with the tree that is passed in
1083 HTreeClass * new_tree = new HTreeClass( *tree );
1084
1085 // Go through each of the pivots and calculate and transform the pivots to match the desired scaling factor
1086 for(int pi = 0; pi < new_tree->NumPivots; ++pi) {
1087 PivotClass piv = tree->Pivot[pi];
1088 Vector3 adjusted_scale = scale;
1089
1090 // If there is no parent, skip
1091 if(!piv.Parent) continue;
1092
1093 // If the pivot is on the flip list, use the Z scale to scale both the Z & Y axis
1094 int index = 0;
1095 while(true) {
1096 if(!flip_list[index]) {
1097 break;
1098 } else if(strcmp(piv.Name, flip_list[index]) == 0) {
1099 adjusted_scale.Y = scale.Z;
1100 break;
1101 }
1102 ++index;
1103 }
1104
1105 // Get the positions of the pivot and the pivot's parent in worldspace & apply the altering scale to it
1106 Vector3 pivot_pos = piv.Transform.Get_Translation();
1107 Vector3 pivot_parent_pos = piv.Parent->Transform.Get_Translation();
1108 pivot_pos.Scale(adjusted_scale);
1109 pivot_parent_pos.Scale(adjusted_scale);
1110
1111 // Get the pivot's parent's inverse transform
1112 Matrix3D parent_inverse_transform;
1113 piv.Parent->Transform.Get_Inverse(parent_inverse_transform);
1114
1115 // Get the new desired vector in worldspace
1116 Vector3 new_relative_vector = pivot_pos - pivot_parent_pos;
1117
1118 // Rotate the new vector by the pivot's parent's inverse transform to put it in local space
1119 new_relative_vector = parent_inverse_transform.Rotate_Vector(new_relative_vector);
1120
1121 // Store the final result in the new HTree
1122 new_tree->Pivot[pi].BaseTransform.Set_Translation( new_relative_vector );
1123 }
1124
1125 return new_tree;
1126}
1127
1128// Morph the bones on the HTree using weights from a number of other HTrees
1130 const float morph_weights[],
1131 const HTreeClass *tree_array[] )
1132{
1133 int i;
1134 assert(num_morph_sources>0);
1135 for(i=0;i<num_morph_sources;i++) {
1136 assert( tree_array[i] );
1137 assert( morph_weights[i]>=0.0f && morph_weights[i]<=1.0f );
1138 }
1139 for(i=0;i<num_morph_sources-1;i++) {
1140 assert( tree_array[i]->NumPivots == tree_array[i+1]->NumPivots );
1141 }
1142
1143 // Clone the first one,
1144 HTreeClass * new_tree = W3DNEWARRAY HTreeClass( *tree_array[0] );
1145
1146 // Then interpolate all the pivots translations
1147 for (int pi = 0; pi < new_tree->NumPivots; pi++) {
1148
1149 Vector3 pos(0.0f,0.0f,0.0f);
1150 for(int nm = 0; nm < num_morph_sources; nm++) {
1151 pos.X += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().X*morph_weights[nm];
1152 pos.Y += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Y*morph_weights[nm];
1153 pos.Z += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Z*morph_weights[nm];
1154 }
1155
1156 new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
1157 }
1158
1159 return new_tree;
1160}
1161
1162// Create an HTree by Interpolating between others
1164 const HTreeClass * tree_a0_b1,
1165 const HTreeClass * tree_a1_b0,
1166 const HTreeClass * tree_a1_b1,
1167 float lerp_a, float lerp_b )
1168{
1169 assert( tree_a0_b0->NumPivots == tree_a0_b1->NumPivots );
1170 assert( tree_a0_b0->NumPivots == tree_a1_b0->NumPivots );
1171 assert( tree_a0_b0->NumPivots == tree_a1_b1->NumPivots );
1172
1173 // Clone the first one,
1174 HTreeClass * new_tree = W3DNEW HTreeClass( *tree_a0_b0 );
1175
1176 // Then interpolate all the pivots translations
1177 Vector3 pos_a0, pos_a1, pos;
1178 for (int pi = 0; pi < new_tree->NumPivots; pi++) {
1179
1180 Vector3::Lerp( tree_a0_b0->Pivot[pi].BaseTransform.Get_Translation(),
1181 tree_a0_b1->Pivot[pi].BaseTransform.Get_Translation(),
1182 lerp_b, &pos_a0 );
1183 Vector3::Lerp( tree_a1_b0->Pivot[pi].BaseTransform.Get_Translation(),
1184 tree_a1_b1->Pivot[pi].BaseTransform.Get_Translation(),
1185 lerp_b, &pos_a1 );
1186 Vector3::Lerp( pos_a0, pos_a1, lerp_a, &pos );
1187
1188 new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
1189 }
1190
1191 return new_tree;
1192}
1193
1194// Create an HTree by Interpolating between others
1196 const HTreeClass * tree_a,
1197 const HTreeClass * tree_b,
1198 float a_scale, float b_scale )
1199{
1201 assert( tree_base->NumPivots == tree_a->NumPivots );
1202 assert( tree_base->NumPivots == tree_b->NumPivots );
1203
1204 // Clone the first one,
1205 HTreeClass * new_tree = W3DNEW HTreeClass( *tree_base );
1206
1207 float a_scale_abs = WWMath::Fabs( a_scale );
1208 float b_scale_abs = WWMath::Fabs( b_scale );
1209
1210 if ( a_scale_abs + b_scale_abs > 0 ) {
1211
1212 // Then interpolate all the pivots translations
1213 Vector3 pos_a, pos_b, pos;
1214 for (int pi = 0; pi < new_tree->NumPivots; pi++) {
1215
1216 Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
1217 tree_a->Pivot[pi].BaseTransform.Get_Translation(),
1218 a_scale, &pos_a );
1219 Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
1220 tree_b->Pivot[pi].BaseTransform.Get_Translation(),
1221 b_scale, &pos_b );
1222
1223 pos = (pos_a * a_scale_abs + pos_b * b_scale_abs ) / ( a_scale_abs + b_scale_abs );
1224
1225 new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
1226 }
1227 }
1228
1229 return new_tree;
1230}
1231
#define NULL
Definition BaseType.h:92
Color scale(const Color &a, const Color &b)
Definition GameMtl.cpp:722
#define W3D_NAME_LEN
Definition w3d_file.h:319
@ W3D_CHUNK_HIERARCHY_HEADER
Definition w3d_file.h:397
@ W3D_CHUNK_PIVOTS
Definition w3d_file.h:398
#define W3D_MAKE_VERSION(major, minor)
Definition w3d_file.h:315
#define W3DNEWARRAY
Definition always.h:110
#define MIN(a, b)
Definition always.h:189
#define W3DNEW
Definition always.h:109
#define MSGW3DNEWARRAY(MSG)
Definition always.h:108
#define MSGW3DNEW(MSG)
Definition always.h:107
WWINLINE int Get_Bit(int frame) const
Definition motchan.h:191
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
virtual void Get_Orientation(int pividx, float frame)
Definition hanim.h:102
virtual void Get_Translation(int pividx, float frame)
Definition hanim.h:101
virtual void Get_Transform(Matrix3D &, int pividx, float frame) const =0
virtual bool Get_Visibility(int pividx, float frame)=0
virtual int Get_Num_Pivots(void) const =0
float Get_Frame(int indx)
Definition hanim.cpp:394
float Get_Weight(int indx)
Definition hanim.cpp:426
HAnimClass * Get_Motion(int indx)
Definition hanim.cpp:364
HAnimClass * Peek_Motion(int indx)
Definition hanim.cpp:377
PivotMapClass * Get_Pivot_Weight_Map(int indx)
Definition hanim.cpp:442
int Get_Num_Anims(void)
Definition hanim.h:239
int Get_Num_Pivots(void) const
Definition hrawanim.h:108
int Get_Num_Frames(void)
Definition hrawanim.h:96
void Init_Default(void)
Definition htree.cpp:85
int Get_Parent_Index(int bone_indx) const
Definition htree.cpp:968
int Load_W3D(ChunkLoadClass &cload)
Definition htree.cpp:176
void Blend_Update(const Matrix3D &root, HAnimClass *motion0, float frame0, HAnimClass *motion1, float frame1, float percentage)
Definition htree.cpp:701
void Combo_Update(const Matrix3D &root, HAnimComboClass *anim)
Definition htree.cpp:773
void Scale(float factor)
Definition htree.cpp:982
void Base_Update(const Matrix3D &root)
Definition htree.cpp:531
HTreeClass(void)
Definition htree.cpp:78
@ LOAD_ERROR
Definition htree.h:82
void Capture_Bone(int boneindex)
Definition htree.cpp:1001
bool Simple_Evaluate_Pivot(HAnimClass *motion, int pivot_index, float frame, const Matrix3D &obj_tm, Matrix3D *end_tm) const
Definition htree.cpp:384
void Control_Bone(int boneindex, const Matrix3D &relative_tm, bool world_space_translation=false)
Definition htree.cpp:1038
~HTreeClass(void)
Definition htree.cpp:118
bool Is_Bone_Captured(int boneindex) const
Definition htree.cpp:1031
static HTreeClass * Create_Morphed(int num_morph_sources, const float morph_weights[], const HTreeClass *tree_array[])
Definition htree.cpp:1129
static HTreeClass * Alter_Avatar_HTree(const HTreeClass *tree, Vector3 &scale)
Definition htree.cpp:1072
int Get_Bone_Index(const char *name) const
Definition htree.cpp:922
const char * Get_Bone_Name(int boneid) const
Definition htree.cpp:945
static HTreeClass * Create_Interpolated(const HTreeClass *tree_a0_b0, const HTreeClass *tree_a0_b1, const HTreeClass *tree_a1_b0, const HTreeClass *tree_a1_b1, float lerp_a, float lerp_b)
Definition htree.cpp:1163
void Anim_Update(const Matrix3D &root, HAnimClass *motion, float frame)
Definition htree.cpp:562
void Release_Bone(int boneindex)
Definition htree.cpp:1016
void Get_Bone_Control(int boneindex, Matrix3D &relative_tm) const
Definition htree.cpp:1055
void postMul(const Matrix3D &that)
Definition matrix3d.h:1528
static void Multiply(const Matrix3D &A, const Matrix3D &B, Matrix3D *set_result)
Definition matrix3d.cpp:640
WWINLINE void Set_Translation(const Vector3 &t)
Definition matrix3d.h:219
Vector3 Rotate_Vector(const Vector3 &vect) const
Definition matrix3d.cpp:300
void Translate(float x, float y, float z)
Definition matrix3d.h:670
void preMul(const Matrix3D &that)
Definition matrix3d.h:1519
WWINLINE Vector3 Get_Translation(void) const
Definition matrix3d.h:217
WWINLINE void Make_Identity(void)
Definition matrix3d.h:650
void Get_Inverse(Matrix3D &set_inverse) const
Definition matrix3d.cpp:514
WWINLINE void Get_Vector_As_Quat(int frame, Quaternion &quat) const
Definition motchan.h:138
void Get_Vector(int frame, float *setvec) const
Definition motchan.h:121
WWINLINE void Release_Ref(void) const
Definition refcount.h:146
float X
Definition vector3.h:90
void Scale(const Vector3 &scale)
Definition vector3.h:679
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
WWINLINE void Set(float x, float y, float z)
Definition vector3.h:103
static void Lerp(const Vector3 &a, const Vector3 &b, float alpha, Vector3 *set_result)
Definition vector3.h:535
static WWINLINE float Fabs(float val)
Definition wwmath.h:113
static long Float_To_Long(float f)
Definition wwmath.h:322
else return(RetVal)
int q
Definition test1.cpp:94
void __cdecl Fast_Slerp(Quaternion &res, const Quaternion &p, const Quaternion &q, float alpha)
Definition quat.cpp:441
Matrix3D & Build_Matrix3D(const Quaternion &q, Matrix3D &out)
Definition quat.h:208
MotionChannelClass * X
Definition hrawanim.h:57
MotionChannelClass * Y
Definition hrawanim.h:58
MotionChannelClass * Q
Definition hrawanim.h:63
BitChannelClass * Vis
Definition hrawanim.h:65
MotionChannelClass * Z
Definition hrawanim.h:59
bool Is_Captured() const
Definition pivot.h:80
Matrix3D BaseTransform
Definition pivot.h:92
PivotClass * Parent
Definition pivot.h:91
Matrix3D Transform
Definition pivot.h:93
char Name[W3D_NAME_LEN]
Definition pivot.h:90
bool IsVisible
Definition pivot.h:104
void Capture_Update(void)
Definition pivot.cpp:137
int Index
Definition pivot.h:103
char Name[W3D_NAME_LEN]
Definition w3d_file.h:1355
W3dVectorStruct Translation
Definition w3d_file.h:1364
W3dQuaternionStruct Rotation
Definition w3d_file.h:1366
char Name[W3D_NAME_LEN]
Definition w3d_file.h:1362
uint32 ParentIdx
Definition w3d_file.h:1363
@ MEM_ANIMATION
Definition wwmemlog.h:60
#define WWMEMLOG(category)
Definition wwmemlog.h:183