| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /* $Header: /VSS_Sync/ww3d2/htree.cpp 11 8/29/01 9:49p Vss_sync $ */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Commando / G 3D Library *
- * *
- * $Archive:: /VSS_Sync/ww3d2/htree.cpp $*
- * *
- * Author:: Greg_h *
- * *
- * $Modtime:: 8/29/01 8:36p $*
- * *
- * $Revision:: 11 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * HTreeClass::HTreeClass -- constructor *
- * HTreeClass::~HTreeClass -- destructor *
- * HTreeClass::Load -- loads a hierarchy tree from a file *
- * HTreeClass::read_pivots -- reads the pivots out of a file *
- * HTreeClass::Free -- de-allocate all memory in use *
- * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
- * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
- * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
- * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
- * HTreeClass::Get_Transform -- returns the transformation for the desired pivot *
- * HTreeClass::Find_Bone -- Find a bone by name *
- * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
- * HTreeClass::Update_Parent_Need_Bits -- all "needed" children force their parents to be nee*
- * HTreeClass::HTreeClass -- copy constructor *
- * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "htree.h"
- #include "hanim.h"
- #include "hcanim.h"
- #include <string.h>
- #include <assert.h>
- #include "wwmath.h"
- #include "chunkio.h"
- #include "w3d_file.h"
- #include "wwmemlog.h"
- #include "hrawanim.h"
- #include "motchan.h"
- /***********************************************************************************************
- * HTreeClass::HTreeClass -- constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- HTreeClass::HTreeClass(void) :
- NumPivots(0),
- Pivot(NULL),
- ScaleFactor(1.0f)
- {
- }
- void HTreeClass::Init_Default(void)
- {
- Free ();
- NumPivots = 1;
- Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
- Pivot[0].Index = 0;
- Pivot[0].Parent = NULL;
- Pivot[0].BaseTransform.Make_Identity();
- Pivot[0].Transform.Make_Identity();
- Pivot[0].IsVisible = true;
- strcpy(Pivot[0].Name,"RootTransform");
- //::strcpy (Name, "Default");
- Name[0] = 0;
- return ;
- }
- /***********************************************************************************************
- * HTreeClass::~HTreeClass -- destructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- HTreeClass::~HTreeClass(void)
- {
- Free();
- }
- /***********************************************************************************************
- * HTreeClass::HTreeClass -- copy constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/4/98 GTH : Created. *
- *=============================================================================================*/
- HTreeClass::HTreeClass(const HTreeClass & src) :
- NumPivots(0),
- Pivot(NULL),
- ScaleFactor(1.0f)
- {
- memcpy(&Name,&src.Name,sizeof(Name));
- NumPivots = src.NumPivots;
- if (NumPivots > 0) {
- Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
- }
- for (int pi = 0; pi < NumPivots; pi++) {
- Pivot[pi] = src.Pivot[pi];
-
- if (src.Pivot[pi].Parent != NULL) {
- Pivot[pi].Parent = &(Pivot[src.Pivot[pi].Parent->Index]);
- } else {
- Pivot[pi].Parent = NULL;
- }
- }
- ScaleFactor = src.ScaleFactor;
- }
- /***********************************************************************************************
- * HTreeClass::Load -- loads a hierarchy tree from a file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- int HTreeClass::Load_W3D(ChunkLoadClass & cload)
- {
- Free();
- /*
- ** Read the first chunk, it should be the hierarchy header
- */
- if (!cload.Open_Chunk()) return LOAD_ERROR;
- if (cload.Cur_Chunk_ID() != W3D_CHUNK_HIERARCHY_HEADER) {
- // ERROR: Expected Hierarchy Header
- return LOAD_ERROR;
- }
-
- W3dHierarchyStruct header;
- if (cload.Read(&header,sizeof(W3dHierarchyStruct)) != sizeof(W3dHierarchyStruct)) {
- return LOAD_ERROR;
- }
- cload.Close_Chunk();
- /*
- ** Check the version, if < 3.0 add a root node for everything
- ** to attach to. The load_pivots function will also have to be
- ** notified of this.
- */
- bool pre30 = false;
- if (header.Version < W3D_MAKE_VERSION(3,0)) {
- header.NumPivots ++;
- pre30 = true;
- }
-
- /*
- ** Allocate the array of pivots
- */
- memcpy(Name,header.Name,W3D_NAME_LEN);
- NumPivots = header.NumPivots;
- if (NumPivots > 0) {
- Pivot = MSGW3DNEWARRAY("HTreeClass::Pivot") PivotClass[NumPivots];
- }
- /*
- ** Now, read in all of the other chunks for this hierarchy.
- */
- while (cload.Open_Chunk()) {
- switch (cload.Cur_Chunk_ID()) {
- case W3D_CHUNK_PIVOTS:
- if (!read_pivots(cload,pre30)) {
- goto Error;
- }
- break;
- default:
- // ERROR: expected W3D_CHUNK_PIVOTS!
- break;
- }
- cload.Close_Chunk();
- }
- return OK;
- Error:
- Free();
- return LOAD_ERROR;
- }
- /***********************************************************************************************
- * HTreeClass::read_pivots -- reads the pivots out of a file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- bool HTreeClass::read_pivots(ChunkLoadClass & cload,bool pre30)
- {
- W3dPivotStruct piv;
- Matrix3D mtx;
-
- int first_piv = 0;
- /*
- ** At (w3d file format) version 3.0, I added a node for the root. Pre-3.0 htrees didn't have
- ** this so we just put one in.
- */
- if (pre30) {
- Pivot[0].Index = 0;
- Pivot[0].Parent = NULL;
- Pivot[0].BaseTransform.Make_Identity();
- Pivot[0].Transform.Make_Identity();
- Pivot[0].IsVisible = true;
- strcpy(Pivot[0].Name,"RootTransform");
- first_piv++;
- }
- for (int pidx=first_piv; pidx < NumPivots; pidx++) {
- if (cload.Read(&piv,sizeof(W3dPivotStruct)) != sizeof(W3dPivotStruct)) {
- return false;
- }
- memcpy(Pivot[pidx].Name,piv.Name,W3D_NAME_LEN);
- Pivot[pidx].Index = pidx;
- Pivot[pidx].BaseTransform.Make_Identity();
- Pivot[pidx].BaseTransform.Translate(Vector3(piv.Translation.X,piv.Translation.Y,piv.Translation.Z));
- #ifdef ALLOW_TEMPORARIES
- Pivot[pidx].BaseTransform =
- Pivot[pidx].BaseTransform *
- Build_Matrix3D(
- Quaternion(
- piv.Rotation.Q[0],
- piv.Rotation.Q[1],
- piv.Rotation.Q[2],
- piv.Rotation.Q[3]
- ),
- mtx
- );
- #else
- Pivot[pidx].BaseTransform.postMul(
- Build_Matrix3D(
- Quaternion(
- piv.Rotation.Q[0],
- piv.Rotation.Q[1],
- piv.Rotation.Q[2],
- piv.Rotation.Q[3]
- ),
- mtx
- )
- );
- #endif
- /*
- ** At version 3.0 a root node was added, this "fixes up" pre-3.0 files
- ** to have that root node
- */
- if (pre30) {
- piv.ParentIdx += 1;
- }
- /*
- ** Set the parent pointer. The first pivot will have a parent index
- ** of -1 (in post-3.0 files) so set its parent to NULL.
- */
- if (piv.ParentIdx == -1) {
- Pivot[pidx].Parent = NULL;
- assert(pidx == 0);
- } else {
- Pivot[pidx].Parent = &(Pivot[piv.ParentIdx]);
- }
- }
- Pivot[0].Transform.Make_Identity();
- Pivot[0].IsVisible = true;
- return true;
- }
- /***********************************************************************************************
- * HTreeClass::Free -- de-allocate all memory in use *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- void HTreeClass::Free(void)
- {
- if (Pivot != NULL) {
- delete[] Pivot;
- Pivot = NULL;
- }
- NumPivots = 0;
- // Also clean up other members:
- ScaleFactor = 1.0f;
- }
- /***********************************************************************************************
- * HTreeClass::Simple_Evaluate_Pivot -- Returns the transform of a pivot at the given frame. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/13/2000 PDS : Created. *
- *=============================================================================================*/
- bool HTreeClass::Simple_Evaluate_Pivot
- (
- HAnimClass * motion,
- int pivot_index,
- float frame,
- const Matrix3D & obj_tm,
- Matrix3D * end_tm
- ) const
- {
- bool retval = false;
- end_tm->Make_Identity ();
- if ( motion != NULL &&
- end_tm != NULL &&
- pivot_index >= 0 &&
- pivot_index < NumPivots)
- {
- //
- // Loop over the hierarchy of pivots that this pivot is
- // attached to and transform each.
- //
- for ( PivotClass *pivot = &Pivot[pivot_index];
- pivot != NULL && pivot->Parent != NULL;
- pivot = pivot->Parent)
- {
- //
- // Build a matrix that represents the animation for this pivot
- //
- Matrix3D anim_tm;
- motion->Get_Transform(anim_tm, pivot->Index, frame);
- // Quaternion q;
- // motion->Get_Orientation (q, pivot->Index, frame);
- // Matrix3D anim_tm = ::Build_Matrix3D(q);
- Vector3 trans;
- anim_tm.Get_Translation(&trans);
- anim_tm.Set_Translation(trans * ScaleFactor);
- //
- // Transform the animation transform by the 'relative-to-parent' transform.
- //
- Matrix3D curr_tm;
- Matrix3D::Multiply(pivot->BaseTransform, anim_tm, &curr_tm);
- //
- // Transform the return value by this transform
- //
- #ifdef ALLOW_TEMPORARIES
- Matrix3D::Multiply (curr_tm, *end_tm, end_tm);
- #else
- end_tm->preMul(curr_tm);
- #endif
- }
- //
- // Transform the return value by the object's transform
- //
- #ifdef ALLOW_TEMPORARIES
- Matrix3D::Multiply (obj_tm, *end_tm, end_tm);
- #else
- end_tm->preMul(obj_tm);
- #endif
- // Success!
- retval = true;
- }
- return retval;
- }
- /***********************************************************************************************
- * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- void HTreeClass::Base_Update(const Matrix3D & root)
- {
- PivotClass *pivot;
- Pivot[0].Transform = root;
- Pivot[0].IsVisible = true;
- for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
-
- pivot = &Pivot[piv_idx];
-
- assert(pivot->Parent != NULL);
- Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
- pivot->IsVisible = 1;
- if (pivot->Is_Captured()) pivot->Capture_Update();
- }
- }
- /***********************************************************************************************
- * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 08/11/1997 GH : Created. *
- *=============================================================================================*/
- void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float frame)
- {
- PivotClass *pivot;
- Matrix3D mtx;
- Pivot[0].Transform = root;
- Pivot[0].IsVisible = true;
- int num_anim_pivots = motion->Get_Num_Pivots ();
- for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
- pivot = &Pivot[piv_idx];
- // base pose
- assert(pivot->Parent != NULL);
- Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
-
- // Don't update this pivot if the HTree doesn't have animation data for it...
- if (piv_idx < num_anim_pivots) {
-
- // animation
- Vector3 trans;
- motion->Get_Translation(trans,piv_idx,frame);
- pivot->Transform.Translate(trans * ScaleFactor);
- Quaternion q;
- motion->Get_Orientation(q,piv_idx,frame);
- ::Build_Matrix3D(q,mtx);
- #ifdef ALLOW_TEMPORARIES
- pivot->Transform = pivot->Transform * mtx;
- #else
- pivot->Transform.postMul(mtx);
- #endif
- // visibility
- pivot->IsVisible = motion->Get_Visibility(piv_idx,frame);
- }
- if (pivot->Is_Captured())
- {
- pivot->Capture_Update();
- pivot->IsVisible = true;
- }
- }
- }
-
- /*Customized version of the above which excludes interpolation and assumes HRawAnimClass
- For use by 'Generals' -MW*/
- void HTreeClass::Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame)
- {
- PivotClass *pivot,*endpivot,*lastAnimPivot;
- Pivot[0].Transform = root;
- Pivot[0].IsVisible = true;
- int num_anim_pivots = motion->Get_Num_Pivots ();
- //Get integer frame
- int iframe=WWMath::Float_To_Long(frame);
- if (iframe >= motion->Get_Num_Frames())
- iframe = 0;
- Vector3 trans;
- Quaternion q;
- Matrix3D mtx;
- struct NodeMotionStruct * nodeMotion = ((HRawAnimClass*)motion)->Get_Node_Motion_Array();
- nodeMotion += 1; //skip the root node
- pivot = &Pivot[1];
- endpivot=pivot+(NumPivots-1);
- lastAnimPivot = &Pivot[num_anim_pivots];
- for (int piv_idx=1; pivot < endpivot; pivot++,nodeMotion++) {
- // base pose
- assert(pivot->Parent != NULL);
- Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
-
- // Don't update this pivot if the HTree doesn't have animation data for it...
- if (pivot < lastAnimPivot)
- {
-
- // animation
- trans.Set(0.0f,0.0f,0.0f);
- Matrix3D *xform=&pivot->Transform;
- if (nodeMotion->X != NULL)
- nodeMotion->X->Get_Vector(iframe,&(trans[0]));
- if (nodeMotion->Y != NULL)
- nodeMotion->Y->Get_Vector(iframe,&(trans[1]));
- if (nodeMotion->Z != NULL)
- nodeMotion->Z->Get_Vector(iframe,&(trans[2]));
- if (ScaleFactor == 1.0f)
- xform->Translate(trans);
- else
- xform->Translate(trans*ScaleFactor);
- if (nodeMotion->Q != NULL)
- { nodeMotion->Q->Get_Vector_As_Quat(iframe, q);
- #ifdef ALLOW_TEMPORARIES
- *xform = *xform * ::Build_Matrix3D(q,mtx);
- #else
- xform->postMul(::Build_Matrix3D(q,mtx));
- #endif
- }
- // visibility
- if (nodeMotion->Vis != NULL)
- pivot->IsVisible=(nodeMotion->Vis->Get_Bit(iframe) == 1);
- else
- pivot->IsVisible=1;
- }
- if (pivot->Is_Captured())
- {
- pivot->Capture_Update();
- pivot->IsVisible = true;
- }
- }
- }
- /***********************************************************************************************
- * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/4/98 GTH : Created. *
- *=============================================================================================*/
- void HTreeClass::Blend_Update
- (
- const Matrix3D & root,
- HAnimClass * motion0,
- float frame0,
- HAnimClass * motion1,
- float frame1,
- float percentage // 0.0 = motion0. 1.0 = motion1
- )
- {
- PivotClass *pivot;
- Matrix3D mtx;
- Pivot[0].Transform = root;
- Pivot[0].IsVisible = true;
- int num_anim_pivots = MIN( motion0->Get_Num_Pivots (), motion1->Get_Num_Pivots () );
- for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
- pivot = &Pivot[piv_idx];
- assert(pivot->Parent != NULL);
- Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
- if (piv_idx < num_anim_pivots) {
- // interpolated translation
- Vector3 trans0;
- motion0->Get_Translation(trans0,piv_idx,frame0);
- Vector3 trans1;
- motion1->Get_Translation(trans1,piv_idx,frame1);
- Vector3 lerped = (1.0 - percentage) * trans0 + (percentage) * trans1;
- pivot->Transform.Translate(lerped * ScaleFactor);
- // interpolated rotation
- Quaternion q0;
- motion0->Get_Orientation(q0,piv_idx,frame0);
- Quaternion q1;
- motion1->Get_Orientation(q1,piv_idx,frame1);
- Quaternion q;
- Fast_Slerp(q,q0,q1,percentage);
- #ifdef ALLOW_TEMPORARIES
- pivot->Transform = pivot->Transform * Build_Matrix3D(q);
- #else
- pivot->Transform.postMul(Build_Matrix3D(q,mtx));
- #endif
- pivot->IsVisible = (motion0->Get_Visibility(piv_idx,frame0) || motion1->Get_Visibility(piv_idx,frame1));
- }
- if (pivot->Is_Captured())
- {
- pivot->Capture_Update();
- pivot->IsVisible = true;
- }
- }
- }
- /***********************************************************************************************
- * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/4/98 GTH : Created. *
- *=============================================================================================*/
- void HTreeClass::Combo_Update
- (
- const Matrix3D & root,
- HAnimComboClass *anim
- )
- {
- PivotClass *pivot;
- Matrix3D mtx;
- Pivot[0].Transform = root;
- Pivot[0].IsVisible = true;
-
- int num_anim_pivots = 100000;
- for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
- num_anim_pivots = MIN( num_anim_pivots, anim->Peek_Motion( anim_num )->Get_Num_Pivots() );
- }
- if ( num_anim_pivots == 100000 ) {
- num_anim_pivots = 0;
- }
- for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
-
- pivot = &Pivot[piv_idx];
- assert(pivot->Parent != NULL);
- Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
-
- if (piv_idx < num_anim_pivots) {
- #define ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
- Vector3 trans(0,0,0);
- Quaternion q0;
- Quaternion q1;
- #ifndef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
- float last_weight = 0;
- #endif
- float weight_total = 0;
- int wcount = 0;
- for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
- HAnimClass *motion = anim->Get_Motion( anim_num );
- if ( motion != NULL ) {
- float frame_num = anim->Get_Frame( anim_num );
- PivotMapClass * pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
- //float *pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
- float weight = anim->Get_Weight( anim_num );
- if ( pivot_map != NULL ) {
- weight *= (*pivot_map)[piv_idx];
- // GREG - Pivot maps are ref counted so shouldn't we
- // release the rivot map here?
- pivot_map->Release_Ref();
- }
- if ( weight != 0.0 ) {
- wcount++;
- Vector3 temp_trans;
- motion->Get_Translation( temp_trans, piv_idx, frame_num );
- trans += weight * ScaleFactor * temp_trans;
- weight_total += weight;
- #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
- motion->Get_Orientation(q1,piv_idx, frame_num );
- if ( wcount == 1 ) {
- q0 = q1;
- } else {
- Fast_Slerp(q0, q0, q1, weight / weight_total );
- }
- #else
- q0 = q1;
- motion->Get_Orientation(q1, piv_idx, frame_num );
- last_weight = weight;
- #endif
- }
- motion->Release_Ref();
- }
- }
- #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
- if (weight_total != 0.0f ) {
- // SKB: Removed assert because I have a case where I don't want normalization.
- // One anim moves X, the other moves Y. Assert was just in to warn programmers.
- // WWASSERT(WWMath::Fabs( weight_total - 1.0 ) < WWMATH_EPSILON);
- pivot->Transform.Translate(trans);
- #ifdef ALLOW_TEMPORARIES
- pivot->Transform = pivot->Transform * Build_Matrix3D(q0);
- #else
- pivot->Transform.postMul(Build_Matrix3D(q0,mtx));
- #endif
- }
- #else
- if (( weight_total != 0.0f ) && (wcount >= 2)) {
-
- pivot->Transform.Translate( trans / weight_total );
- Quaternion q = Slerp_( q0, q1, last_weight / weight_total );
- pivot->Transform = pivot->Transform * Build_Matrix3D(q);
- } else if (weight_total != 0.0f) {
- pivot->Transform.Translate( trans / weight_total );
- pivot->Transform = pivot->Transform * Build_Matrix3D(q1);
- }
- #endif
- pivot->IsVisible = false;
- for ( anim_num = 0; (anim_num < anim->Get_Num_Anims()) && (!pivot->IsVisible); anim_num++ ) {
- HAnimClass *motion = anim->Get_Motion( anim_num );
- if ( motion != NULL ) {
- float frame_num = anim->Get_Frame( anim_num );
- pivot->IsVisible |= motion->Get_Visibility(piv_idx,frame_num);
- motion->Release_Ref();
- }
- }
- }
- if (pivot->Is_Captured())
- {
- pivot->Capture_Update();
- pivot->IsVisible = true;
- }
- }
- }
- /***********************************************************************************************
- * HTreeClass::Find_Bone -- Find a bone by name *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/4/97 GTH : Created. *
- *=============================================================================================*/
- int HTreeClass::Get_Bone_Index(const char * name) const
- {
- for (int i=0; i < NumPivots; i++) {
- if (stricmp(Pivot[i].Name,name) == 0) {
- return i;
- }
- }
- return 0;
- }
- /***********************************************************************************************
- * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/4/97 GTH : Created. *
- *=============================================================================================*/
- const char * HTreeClass::Get_Bone_Name(int boneidx) const
- {
- assert(boneidx >= 0);
- assert(boneidx < NumPivots);
- return Pivot[boneidx].Name;
- }
- /***********************************************************************************************
- * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
- * *
- * INPUT: *
- * boneidx - the bone you are interested in *
- * *
- * OUTPUT: *
- * the index of that bone's parent *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/12/2000 gth : Created. *
- *=============================================================================================*/
- int HTreeClass::Get_Parent_Index(int boneidx) const
- {
- assert(boneidx >= 0);
- assert(boneidx < NumPivots);
- if (Pivot[boneidx].Parent != NULL) {
- return Pivot[boneidx].Parent->Index;
- } else {
- return 0;
- }
- }
- // Scale this HTree by a constant factor:
- void HTreeClass::Scale(float factor)
- {
- if (factor == 1.0f) return;
- // Scale pivot translations
- for (int i = 0; i < NumPivots; i++) {
- Matrix3D &pivot_transform = Pivot[i].BaseTransform;
- Vector3 pivot_translation;
- pivot_transform.Get_Translation(&pivot_translation);
- pivot_translation *= factor;
- pivot_transform.Set_Translation(pivot_translation);
- }
- // Set state used later to scale animations:
- ScaleFactor *= factor;
- }
- void HTreeClass::Capture_Bone(int boneindex)
- {
- assert(boneindex >= 0);
- assert(boneindex < NumPivots);
- #ifdef LAZY_CAP_MTX_ALLOC
- if (Pivot[boneindex].CapTransformPtr == NULL)
- {
- Pivot[boneindex].CapTransformPtr = MSGW3DNEW("PivotClassCaptureBoneMtx") DynamicMatrix3D;
- Pivot[boneindex].CapTransformPtr->Mat.Make_Identity();
- }
- #else
- Pivot[boneindex].IsCaptured = true;
- #endif
- }
- void HTreeClass::Release_Bone(int boneindex)
- {
- assert(boneindex >= 0);
- assert(boneindex < NumPivots);
- #ifdef LAZY_CAP_MTX_ALLOC
- if (Pivot[boneindex].CapTransformPtr)
- {
- delete Pivot[boneindex].CapTransformPtr;
- Pivot[boneindex].CapTransformPtr = NULL;
- }
- #else
- Pivot[boneindex].IsCaptured = false;
- #endif
- }
- bool HTreeClass::Is_Bone_Captured(int boneindex) const
- {
- assert(boneindex >= 0);
- assert(boneindex < NumPivots);
- return Pivot[boneindex].Is_Captured();
- }
- void HTreeClass::Control_Bone(int boneindex,const Matrix3D & relative_tm,bool world_space_translation)
- {
- assert(boneindex >= 0);
- assert(boneindex < NumPivots);
- assert(Pivot[boneindex].Is_Captured());
- #ifdef LAZY_CAP_MTX_ALLOC
- if (Pivot[boneindex].CapTransformPtr == NULL)
- return;
- Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
- Pivot[boneindex].CapTransformPtr->Mat = relative_tm;
- #else
- Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
- Pivot[boneindex].CapTransform = relative_tm;
- #endif
- }
- // Morph the bones on the HTree using weights from a number of other HTrees
- HTreeClass * HTreeClass::Create_Morphed( int num_morph_sources,
- const float morph_weights[],
- const HTreeClass *tree_array[] )
- {
- int i;
- assert(num_morph_sources>0);
- for(i=0;i<num_morph_sources;i++) {
- assert( tree_array[i] );
- assert( morph_weights[i]>=0.0f && morph_weights[i]<=1.0f );
- }
- for(i=0;i<num_morph_sources-1;i++) {
- assert( tree_array[i]->NumPivots == tree_array[i+1]->NumPivots );
- }
- // Clone the first one,
- HTreeClass * new_tree = W3DNEWARRAY HTreeClass( *tree_array[0] );
- // Then interpolate all the pivots translations
- for (int pi = 0; pi < new_tree->NumPivots; pi++) {
- Vector3 pos(0.0f,0.0f,0.0f);
- for(int nm = 0; nm < num_morph_sources; nm++) {
- pos.X += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().X*morph_weights[nm];
- pos.Y += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Y*morph_weights[nm];
- pos.Z += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Z*morph_weights[nm];
- }
- new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
- }
- return new_tree;
- }
- // Create an HTree by Interpolating between others
- HTreeClass * 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 )
- {
- assert( tree_a0_b0->NumPivots == tree_a0_b1->NumPivots );
- assert( tree_a0_b0->NumPivots == tree_a1_b0->NumPivots );
- assert( tree_a0_b0->NumPivots == tree_a1_b1->NumPivots );
- // Clone the first one,
- HTreeClass * new_tree = W3DNEW HTreeClass( *tree_a0_b0 );
- // Then interpolate all the pivots translations
- Vector3 pos_a0, pos_a1, pos;
- for (int pi = 0; pi < new_tree->NumPivots; pi++) {
- Vector3::Lerp( tree_a0_b0->Pivot[pi].BaseTransform.Get_Translation(),
- tree_a0_b1->Pivot[pi].BaseTransform.Get_Translation(),
- lerp_b, &pos_a0 );
- Vector3::Lerp( tree_a1_b0->Pivot[pi].BaseTransform.Get_Translation(),
- tree_a1_b1->Pivot[pi].BaseTransform.Get_Translation(),
- lerp_b, &pos_a1 );
- Vector3::Lerp( pos_a0, pos_a1, lerp_a, &pos );
- new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
- }
- return new_tree;
- }
- // Create an HTree by Interpolating between others
- HTreeClass * HTreeClass::Create_Interpolated(const HTreeClass * tree_base,
- const HTreeClass * tree_a,
- const HTreeClass * tree_b,
- float a_scale, float b_scale )
- {
- WWMEMLOG(MEM_ANIMATION);
- assert( tree_base->NumPivots == tree_a->NumPivots );
- assert( tree_base->NumPivots == tree_b->NumPivots );
- // Clone the first one,
- HTreeClass * new_tree = W3DNEW HTreeClass( *tree_base );
- float a_scale_abs = WWMath::Fabs( a_scale );
- float b_scale_abs = WWMath::Fabs( b_scale );
- if ( a_scale_abs + b_scale_abs > 0 ) {
- // Then interpolate all the pivots translations
- Vector3 pos_a, pos_b, pos;
- for (int pi = 0; pi < new_tree->NumPivots; pi++) {
- Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
- tree_a->Pivot[pi].BaseTransform.Get_Translation(),
- a_scale, &pos_a );
- Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
- tree_b->Pivot[pi].BaseTransform.Get_Translation(),
- b_scale, &pos_b );
- pos = (pos_a * a_scale_abs + pos_b * b_scale_abs ) / ( a_scale_abs + b_scale_abs );
- new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
- }
- }
- return new_tree;
- }
|