| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- /*
- ** Command & Conquer Generals Zero Hour(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: /Commando/Code/ww3d2/hanim.cpp 3 12/13/01 7:01p Patrick $ */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Commando / G 3D Library *
- * *
- * $Archive:: /Commando/Code/ww3d2/hanim.cpp $*
- * *
- * Author:: Greg_h *
- * *
- * $Modtime:: 12/13/01 6:54p $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "hanim.h"
- #include "assetmgr.h"
- #include "htree.h"
- #include "motchan.h"
- #include "chunkio.h"
- #include "w3d_file.h"
- #include "wwdebug.h"
- #include <string.h>
- #include <nstrdup.h>
- /*
- **
- ** HAnimComboClass
- **
- **
- */
- NamedPivotMapClass::~NamedPivotMapClass(void)
- {
- }
- NamedPivotMapClass::WeightInfoStruct & NamedPivotMapClass::WeightInfoStruct::operator = (WeightInfoStruct const &that)
- {
- if(Name) delete [] Name;
- assert(that.Name != 0);
- Name = nstrdup(that.Name);
- Weight = that.Weight;
- return *this;
- }
- // add a name & weight to the arrays
- void NamedPivotMapClass::Add(const char *Name, float Weight)
- {
- WeightInfoStruct info;
- info.Name = (char *) Name;
- info.Weight = Weight;
- WeightInfo.Add(info);
- info.Name = 0;
- }
- // configure the base pivot map using the specified tree
- void NamedPivotMapClass::Update_Pivot_Map(const HTreeClass *Tree)
- {
- // first, resize the base pivot map to fit the tree
- int numPivots = Tree->Num_Pivots();
- Resize(numPivots);
- ActiveCount = numPivots;
- // first, reset all weights to 1 (the default)
- while(numPivots--) {
- (*this)[numPivots] = 1.0f;
- }
- // for each named pivot, find the correct index and set the weight if the indicated bone is present
- // note: there is no check for redundant names
- int count = WeightInfo.Count();
- while(count--) {
- int actualPivot = Tree->Get_Bone_Index(WeightInfo[count].Name);
- if(actualPivot != -1) {
- (*this)[actualPivot] = WeightInfo[count].Weight;
- }
- }
- }
- /*
- **
- */
- DEFINE_AUTO_POOL(HAnimComboDataClass,256);
- HAnimComboDataClass::HAnimComboDataClass(bool shared)
- : Shared(shared), HAnim(0), PivotMap(0), Frame(0), PrevFrame(0), Weight(1)
- {}
- HAnimComboDataClass::HAnimComboDataClass(const HAnimComboDataClass &src)
- : PivotMap(src.Get_Pivot_Map()),
- HAnim(src.Get_HAnim())
- {
- Shared = src.Is_Shared();
- Frame = src.Get_Frame();
- PrevFrame = src.Get_Prev_Frame();
- Weight = src.Get_Weight();
- }
- void HAnimComboDataClass::Copy(const HAnimComboDataClass *src)
- {
- if(src) {
- HAnim = src->Get_HAnim();
- PivotMap = src->Get_Pivot_Map();
- Frame = src->Get_Frame();
- PrevFrame = src->Get_Prev_Frame();
- Weight = src->Get_Weight();
- } else {
- HAnim = 0;
- PivotMap = 0;
- Frame = 0;
- PrevFrame = 0;
- Weight = 1;
- }
- }
- HAnimComboDataClass::~HAnimComboDataClass(void)
- {
- if(HAnim)
- HAnim->Release_Ref();
- if(PivotMap)
- PivotMap->Release_Ref();
- }
- void HAnimComboDataClass::Clear(void)
- {
- if ( HAnim != NULL ) {
- HAnim->Release_Ref();
- HAnim = NULL;
- }
- // not sure if the pivot map should be deleted or just have everything set to one.
- // removing it effectively sets it to one, so that's what I'm doing for now.
- if(PivotMap) {
- PivotMap->Release_Ref();
- PivotMap = NULL;
- }
- Frame = 0.0f;
- PrevFrame = 0.0f;
- Weight = 1.0;
- PivotMap = NULL;
- }
- void HAnimComboDataClass::Set_HAnim(HAnimClass *motion)
- {
- if ( motion != NULL ) {
- motion->Add_Ref();
- }
- if ( HAnim != NULL ) {
- HAnim->Release_Ref();
- }
- HAnim = motion;
- }
- void HAnimComboDataClass::Set_Pivot_Map(PivotMapClass *map)
- {
- if ( map != NULL ) {
- map->Add_Ref();
- }
- if ( PivotMap != NULL ) {
- PivotMap->Release_Ref();
- }
- PivotMap = map;
- }
- /*
- ** This function will replace the current pivot map (if any) with another pivot map that is
- ** set to 1 for only those pivot indices that actually have data.
- */
- void HAnimComboDataClass::Build_Active_Pivot_Map(void)
- {
- if ( PivotMap != NULL ) {
- PivotMap->Release_Ref();
- }
- if(HAnim == NULL) {
- PivotMap = 0;
- return;
- }
- int numpivots = HAnim->Get_Num_Pivots();
- PivotMap = NEW_REF( PivotMapClass, ());
- PivotMap->Resize(numpivots);
- int count = 0;
- while(count < numpivots) {
- if(HAnim->Is_Node_Motion_Present(count)) {
- PivotMap->Add(1);
- } else {
- PivotMap->Add(0);
- }
- count++;
- }
- }
- /*
- ** HAnimComboClass
- **
- **
- */
- HAnimComboClass::HAnimComboClass(void)
- {}
- HAnimComboClass::HAnimComboClass( int num_animations )
- {
- HAnimComboData.Resize(num_animations);
- while(num_animations--) {
- HAnimComboData.Add(new HAnimComboDataClass());
- }
- }
- HAnimComboClass::~HAnimComboClass(void)
- {
- Reset();
- }
- void HAnimComboClass::Clear( void )
- {
- int numAnimations = HAnimComboData.Count();
- while ( numAnimations-- ) {
- HAnimComboDataClass *data = HAnimComboData[numAnimations];
- if(data && (! data->Is_Shared()))
- data->Clear();
- }
- }
- void HAnimComboClass::Reset( void )
- {
- int numAnimations = HAnimComboData.Count();
- while ( numAnimations-- ) {
- HAnimComboDataClass *data = HAnimComboData[numAnimations];
- if(data && (! data->Is_Shared())) {
- delete data;
- }
- }
- HAnimComboData.Reset_Active();
- }
- bool HAnimComboClass::Normalize_Weights(void)
- {
- // NOTE: This can only work if either no anims have pivot weight maps (in which case we will
- // adjust the anim weights to ensure normalization), or else if all do (in which case we will
- // adjust the pivot maps). Otherwise we do nothing and return false.
- int anim_count = Get_Num_Anims();
- if (!anim_count) return true; // Trivially succeeded
-
- // Loop over all anims. Check if all or none have pivot maps, and also calculate the minimum
- // number of pivots.
- int anim_idx = 0;
- bool all_pivot_maps = true;
- bool none_pivot_maps = true;
- int num_anim_pivots = 100000;
- for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
- num_anim_pivots = MIN(num_anim_pivots, Peek_Motion(anim_idx)->Get_Num_Pivots());
- bool has_pivot_map = Peek_Pivot_Weight_Map(anim_idx) != NULL;
- all_pivot_maps &= has_pivot_map;
- none_pivot_maps &= !has_pivot_map;
- }
- if ( num_anim_pivots == 100000 ) {
- num_anim_pivots = 0;
- }
- if (none_pivot_maps) {
- // Calculate total weight of all active anims, ensure it is very close to 1.
- float weight_total = 0.0f;
- for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
- if (Peek_Motion(anim_idx) != NULL ) {
- float weight = Get_Weight(anim_idx);
- weight_total += weight;
- }
- }
- // weight_total should be very close to 1. If not, normalize this pivot's weights
- if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
- float oo_total = 1.0f / weight_total;
- for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
- if (Peek_Motion(anim_idx) != NULL ) {
- Set_Weight(anim_idx, Get_Weight(anim_idx) * oo_total);
- }
- }
- }
- } else {
- if (all_pivot_maps) {
- // For each pivot, calculate total weight of all active anims, ensure close to 1.
- for (int piv_idx = 1; piv_idx < num_anim_pivots; piv_idx++) {
- float weight_total = 0.0f;
- for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
- if (Peek_Motion(anim_idx) != NULL ) {
- float weight = Get_Weight(anim_idx) * (*Peek_Pivot_Weight_Map(anim_idx))[piv_idx];
- weight_total += weight;
- }
- }
- // weight_total should be very close to 1. If not, normalize this pivot's weights
- if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
- float oo_total = 1.0f / weight_total;
- for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
- if (Peek_Motion(anim_idx) != NULL ) {
- PivotMapClass *pivot_map = Get_Pivot_Weight_Map(anim_idx);
- float new_weight = (*pivot_map)[piv_idx] * oo_total;
- (*pivot_map)[piv_idx] = new_weight;
- pivot_map->Release_Ref();
- }
- }
- }
- }
- } else {
- return false;
- }
- }
- return true;
- }
- void HAnimComboClass::Set_Motion( int index, HAnimClass *motion )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- data->Set_HAnim(motion);
- }
- HAnimClass *HAnimComboClass::Get_Motion( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- HAnimClass *anim = data->Peek_HAnim();
- if ( anim != NULL ) {
- anim->Add_Ref();
- }
- return anim;
- }
- HAnimClass *HAnimComboClass::Peek_Motion( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- HAnimClass *anim = data->Peek_HAnim();
- return anim;
- }
- void HAnimComboClass::Set_Frame( int index, float frame )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- data->Set_Frame(frame);
- }
- float HAnimComboClass::Get_Frame( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- return data->Get_Frame();
- }
- void HAnimComboClass::Set_Prev_Frame( int index, float frame )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- data->Set_Prev_Frame(frame);
- }
- float HAnimComboClass::Get_Prev_Frame( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- return data->Get_Prev_Frame();
- }
- void HAnimComboClass::Set_Weight( int index, float weight )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- data->Set_Weight(weight);
- }
- float HAnimComboClass::Get_Weight( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- return data->Get_Weight();
- }
- void HAnimComboClass::Set_Pivot_Weight_Map( int index, PivotMapClass *map )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- data->Set_Pivot_Map(map);
- }
- PivotMapClass *HAnimComboClass::Get_Pivot_Weight_Map( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- return data->Get_Pivot_Map();
- }
- PivotMapClass *HAnimComboClass::Peek_Pivot_Weight_Map( int index )
- {
- HAnimComboDataClass *data = HAnimComboData[index];
- WWASSERT(data);
- return data->Peek_Pivot_Map();
- }
- void HAnimComboClass::Append_Anim_Combo_Data(HAnimComboDataClass * Data)
- {
- HAnimComboData.Add(Data);
- }
- void HAnimComboClass::Remove_Anim_Combo_Data(HAnimComboDataClass * Data)
- {
- HAnimComboData.Delete(Data);
- }
|