hanim.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. ** Command & Conquer Generals(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. /* $Header: /Commando/Code/ww3d2/hanim.cpp 2 1/23/01 2:12p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G 3D Library *
  24. * *
  25. * $Archive:: /Commando/Code/ww3d2/hanim.cpp $*
  26. * *
  27. * Author:: Greg_h *
  28. * *
  29. * $Modtime:: 1/22/01 6:23p $*
  30. * *
  31. * $Revision:: 2 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #include "hanim.h"
  37. #include "assetmgr.h"
  38. #include "htree.h"
  39. #include "motchan.h"
  40. #include "chunkio.h"
  41. #include "w3d_file.h"
  42. #include "wwdebug.h"
  43. #include <string.h>
  44. #include <nstrdup.h>
  45. /*
  46. **
  47. ** HAnimComboClass
  48. **
  49. **
  50. */
  51. NamedPivotMapClass::~NamedPivotMapClass(void)
  52. {
  53. }
  54. NamedPivotMapClass::WeightInfoStruct & NamedPivotMapClass::WeightInfoStruct::operator = (WeightInfoStruct const &that)
  55. {
  56. if(Name) delete [] Name;
  57. assert(that.Name != 0);
  58. Name = nstrdup(that.Name);
  59. Weight = that.Weight;
  60. return *this;
  61. }
  62. // add a name & weight to the arrays
  63. void NamedPivotMapClass::Add(const char *Name, float Weight)
  64. {
  65. WeightInfoStruct info;
  66. info.Name = (char *) Name;
  67. info.Weight = Weight;
  68. WeightInfo.Add(info);
  69. info.Name = 0;
  70. }
  71. // configure the base pivot map using the specified tree
  72. void NamedPivotMapClass::Update_Pivot_Map(const HTreeClass *Tree)
  73. {
  74. // first, resize the base pivot map to fit the tree
  75. int numPivots = Tree->Num_Pivots();
  76. Resize(numPivots);
  77. ActiveCount = numPivots;
  78. // first, reset all weights to 1 (the default)
  79. while(numPivots--) {
  80. (*this)[numPivots] = 1.0f;
  81. }
  82. // for each named pivot, find the correct index and set the weight if the indicated bone is present
  83. // note: there is no check for redundant names
  84. int count = WeightInfo.Count();
  85. while(count--) {
  86. int actualPivot = Tree->Get_Bone_Index(WeightInfo[count].Name);
  87. if(actualPivot != -1) {
  88. (*this)[actualPivot] = WeightInfo[count].Weight;
  89. }
  90. }
  91. }
  92. /*
  93. **
  94. */
  95. DEFINE_AUTO_POOL(HAnimComboDataClass,256);
  96. HAnimComboDataClass::HAnimComboDataClass(bool shared)
  97. : Shared(shared), HAnim(0), PivotMap(0), Frame(0), Weight(1)
  98. {}
  99. HAnimComboDataClass::HAnimComboDataClass(const HAnimComboDataClass &src)
  100. : PivotMap(src.Get_Pivot_Map()),
  101. HAnim(src.Get_HAnim())
  102. {
  103. Shared = src.Is_Shared();
  104. Frame = src.Get_Frame();
  105. Weight = src.Get_Weight();
  106. }
  107. void HAnimComboDataClass::Copy(const HAnimComboDataClass *src)
  108. {
  109. if(src) {
  110. HAnim = src->Get_HAnim();
  111. PivotMap = src->Get_Pivot_Map();
  112. Frame = src->Get_Frame();
  113. Weight = src->Get_Weight();
  114. } else {
  115. HAnim = 0;
  116. PivotMap = 0;
  117. Frame = 0;
  118. Weight = 1;
  119. }
  120. }
  121. HAnimComboDataClass::~HAnimComboDataClass(void)
  122. {
  123. if(HAnim)
  124. HAnim->Release_Ref();
  125. if(PivotMap)
  126. PivotMap->Release_Ref();
  127. }
  128. void HAnimComboDataClass::Clear(void)
  129. {
  130. if ( HAnim != NULL ) {
  131. HAnim->Release_Ref();
  132. HAnim = NULL;
  133. }
  134. // not sure if the pivot map should be deleted or just have everything set to one.
  135. // removing it effectively sets it to one, so that's what I'm doing for now.
  136. if(PivotMap) {
  137. PivotMap->Release_Ref();
  138. PivotMap = NULL;
  139. }
  140. Frame = 0.0f;
  141. Weight = 1.0;
  142. PivotMap = NULL;
  143. }
  144. void HAnimComboDataClass::Set_HAnim(HAnimClass *motion)
  145. {
  146. if ( motion != NULL ) {
  147. motion->Add_Ref();
  148. }
  149. if ( HAnim != NULL ) {
  150. HAnim->Release_Ref();
  151. }
  152. HAnim = motion;
  153. }
  154. void HAnimComboDataClass::Set_Pivot_Map(PivotMapClass *map)
  155. {
  156. if ( map != NULL ) {
  157. map->Add_Ref();
  158. }
  159. if ( PivotMap != NULL ) {
  160. PivotMap->Release_Ref();
  161. }
  162. PivotMap = map;
  163. }
  164. /*
  165. ** This function will replace the current pivot map (if any) with another pivot map that is
  166. ** set to 1 for only those pivot indices that actually have data.
  167. */
  168. void HAnimComboDataClass::Build_Active_Pivot_Map(void)
  169. {
  170. if ( PivotMap != NULL ) {
  171. PivotMap->Release_Ref();
  172. }
  173. if(HAnim == NULL) {
  174. PivotMap = 0;
  175. return;
  176. }
  177. int numpivots = HAnim->Get_Num_Pivots();
  178. PivotMap = NEW_REF( PivotMapClass, ());
  179. PivotMap->Resize(numpivots);
  180. int count = 0;
  181. while(count < numpivots) {
  182. if(HAnim->Is_Node_Motion_Present(count)) {
  183. PivotMap->Add(1);
  184. } else {
  185. PivotMap->Add(0);
  186. }
  187. count++;
  188. }
  189. }
  190. /*
  191. ** HAnimComboClass
  192. **
  193. **
  194. */
  195. HAnimComboClass::HAnimComboClass(void)
  196. {}
  197. HAnimComboClass::HAnimComboClass( int num_animations )
  198. {
  199. HAnimComboData.Resize(num_animations);
  200. while(num_animations--) {
  201. HAnimComboData.Add(new HAnimComboDataClass());
  202. }
  203. }
  204. HAnimComboClass::~HAnimComboClass(void)
  205. {
  206. Reset();
  207. }
  208. void HAnimComboClass::Clear( void )
  209. {
  210. int numAnimations = HAnimComboData.Count();
  211. while ( numAnimations-- ) {
  212. HAnimComboDataClass *data = HAnimComboData[numAnimations];
  213. if(data && (! data->Is_Shared()))
  214. data->Clear();
  215. }
  216. }
  217. void HAnimComboClass::Reset( void )
  218. {
  219. int numAnimations = HAnimComboData.Count();
  220. while ( numAnimations-- ) {
  221. HAnimComboDataClass *data = HAnimComboData[numAnimations];
  222. if(data && (! data->Is_Shared())) {
  223. delete data;
  224. }
  225. }
  226. HAnimComboData.Reset_Active();
  227. }
  228. bool HAnimComboClass::Normalize_Weights(void)
  229. {
  230. // NOTE: This can only work if either no anims have pivot weight maps (in which case we will
  231. // adjust the anim weights to ensure normalization), or else if all do (in which case we will
  232. // adjust the pivot maps). Otherwise we do nothing and return false.
  233. int anim_count = Get_Num_Anims();
  234. if (!anim_count) return true; // Trivially succeeded
  235. // Loop over all anims. Check if all or none have pivot maps, and also calculate the minimum
  236. // number of pivots.
  237. int anim_idx = 0;
  238. bool all_pivot_maps = true;
  239. bool none_pivot_maps = true;
  240. int num_anim_pivots = 100000;
  241. for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
  242. num_anim_pivots = MIN(num_anim_pivots, Peek_Motion(anim_idx)->Get_Num_Pivots());
  243. bool has_pivot_map = Peek_Pivot_Weight_Map(anim_idx) != NULL;
  244. all_pivot_maps &= has_pivot_map;
  245. none_pivot_maps &= !has_pivot_map;
  246. }
  247. if ( num_anim_pivots == 100000 ) {
  248. num_anim_pivots = 0;
  249. }
  250. if (none_pivot_maps) {
  251. // Calculate total weight of all active anims, ensure it is very close to 1.
  252. float weight_total = 0.0f;
  253. for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
  254. if (Peek_Motion(anim_idx) != NULL ) {
  255. float weight = Get_Weight(anim_idx);
  256. weight_total += weight;
  257. }
  258. }
  259. // weight_total should be very close to 1. If not, normalize this pivot's weights
  260. if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
  261. float oo_total = 1.0f / weight_total;
  262. for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
  263. if (Peek_Motion(anim_idx) != NULL ) {
  264. Set_Weight(anim_idx, Get_Weight(anim_idx) * oo_total);
  265. }
  266. }
  267. }
  268. } else {
  269. if (all_pivot_maps) {
  270. // For each pivot, calculate total weight of all active anims, ensure close to 1.
  271. for (int piv_idx = 1; piv_idx < num_anim_pivots; piv_idx++) {
  272. float weight_total = 0.0f;
  273. for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
  274. if (Peek_Motion(anim_idx) != NULL ) {
  275. float weight = Get_Weight(anim_idx) * (*Peek_Pivot_Weight_Map(anim_idx))[piv_idx];
  276. weight_total += weight;
  277. }
  278. }
  279. // weight_total should be very close to 1. If not, normalize this pivot's weights
  280. if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
  281. float oo_total = 1.0f / weight_total;
  282. for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
  283. if (Peek_Motion(anim_idx) != NULL ) {
  284. PivotMapClass *pivot_map = Get_Pivot_Weight_Map(anim_idx);
  285. float new_weight = (*pivot_map)[piv_idx] * oo_total;
  286. (*pivot_map)[piv_idx] = new_weight;
  287. pivot_map->Release_Ref();
  288. }
  289. }
  290. }
  291. }
  292. } else {
  293. return false;
  294. }
  295. }
  296. return true;
  297. }
  298. void HAnimComboClass::Set_Motion( int index, HAnimClass *motion )
  299. {
  300. HAnimComboDataClass *data = HAnimComboData[index];
  301. WWASSERT(data);
  302. data->Set_HAnim(motion);
  303. }
  304. HAnimClass *HAnimComboClass::Get_Motion( int index )
  305. {
  306. HAnimComboDataClass *data = HAnimComboData[index];
  307. WWASSERT(data);
  308. HAnimClass *anim = data->Peek_HAnim();
  309. if ( anim != NULL ) {
  310. anim->Add_Ref();
  311. }
  312. return anim;
  313. }
  314. HAnimClass *HAnimComboClass::Peek_Motion( int index )
  315. {
  316. HAnimComboDataClass *data = HAnimComboData[index];
  317. WWASSERT(data);
  318. HAnimClass *anim = data->Peek_HAnim();
  319. return anim;
  320. }
  321. void HAnimComboClass::Set_Frame( int index, float frame )
  322. {
  323. HAnimComboDataClass *data = HAnimComboData[index];
  324. WWASSERT(data);
  325. data->Set_Frame(frame);
  326. }
  327. float HAnimComboClass::Get_Frame( int index )
  328. {
  329. HAnimComboDataClass *data = HAnimComboData[index];
  330. WWASSERT(data);
  331. return data->Get_Frame();
  332. }
  333. void HAnimComboClass::Set_Weight( int index, float weight )
  334. {
  335. HAnimComboDataClass *data = HAnimComboData[index];
  336. WWASSERT(data);
  337. data->Set_Weight(weight);
  338. }
  339. float HAnimComboClass::Get_Weight( int index )
  340. {
  341. HAnimComboDataClass *data = HAnimComboData[index];
  342. WWASSERT(data);
  343. return data->Get_Weight();
  344. }
  345. void HAnimComboClass::Set_Pivot_Weight_Map( int index, PivotMapClass *map )
  346. {
  347. HAnimComboDataClass *data = HAnimComboData[index];
  348. WWASSERT(data);
  349. data->Set_Pivot_Map(map);
  350. }
  351. PivotMapClass *HAnimComboClass::Get_Pivot_Weight_Map( int index )
  352. {
  353. HAnimComboDataClass *data = HAnimComboData[index];
  354. WWASSERT(data);
  355. return data->Get_Pivot_Map();
  356. }
  357. PivotMapClass *HAnimComboClass::Peek_Pivot_Weight_Map( int index )
  358. {
  359. HAnimComboDataClass *data = HAnimComboData[index];
  360. WWASSERT(data);
  361. return data->Peek_Pivot_Map();
  362. }
  363. void HAnimComboClass::Append_Anim_Combo_Data(HAnimComboDataClass * Data)
  364. {
  365. HAnimComboData.Add(Data);
  366. }
  367. void HAnimComboClass::Remove_Anim_Combo_Data(HAnimComboDataClass * Data)
  368. {
  369. HAnimComboData.Delete(Data);
  370. }