htree.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /*
  2. ** Command & Conquer Renegade(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/htree.cpp 14 10/01/01 6:07p Patrick $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G 3D Library *
  24. * *
  25. * $Archive:: /Commando/Code/ww3d2/htree.cpp $*
  26. * *
  27. * Author:: Greg_h *
  28. * *
  29. * $Modtime:: 10/01/01 6:06p $*
  30. * *
  31. * $Revision:: 14 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * HTreeClass::HTreeClass -- constructor *
  36. * HTreeClass::~HTreeClass -- destructor *
  37. * HTreeClass::Load -- loads a hierarchy tree from a file *
  38. * HTreeClass::read_pivots -- reads the pivots out of a file *
  39. * HTreeClass::Free -- de-allocate all memory in use *
  40. * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
  41. * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
  42. * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
  43. * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
  44. * HTreeClass::Get_Transform -- returns the transformation for the desired pivot *
  45. * HTreeClass::Find_Bone -- Find a bone by name *
  46. * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
  47. * HTreeClass::Update_Parent_Need_Bits -- all "needed" children force their parents to be nee*
  48. * HTreeClass::HTreeClass -- copy constructor *
  49. * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
  50. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  51. #include "htree.h"
  52. #include "hanim.h"
  53. #include "hcanim.h"
  54. #include <string.h>
  55. #include <assert.h>
  56. #include "wwmath.h"
  57. #include "chunkio.h"
  58. #include "w3d_file.h"
  59. #include "wwmemlog.h"
  60. /***********************************************************************************************
  61. * HTreeClass::HTreeClass -- constructor *
  62. * *
  63. * INPUT: *
  64. * *
  65. * OUTPUT: *
  66. * *
  67. * WARNINGS: *
  68. * *
  69. * HISTORY: *
  70. * 08/11/1997 GH : Created. *
  71. *=============================================================================================*/
  72. HTreeClass::HTreeClass(void) :
  73. NumPivots(0),
  74. Pivot(NULL),
  75. ScaleFactor(1.0f)
  76. {
  77. }
  78. void HTreeClass::Init_Default(void)
  79. {
  80. Free ();
  81. NumPivots = 1;
  82. Pivot = new PivotClass[NumPivots];
  83. Pivot[0].Index = 0;
  84. Pivot[0].Parent = NULL;
  85. Pivot[0].BaseTransform.Make_Identity();
  86. Pivot[0].Transform.Make_Identity();
  87. Pivot[0].IsVisible = true;
  88. strcpy(Pivot[0].Name,"RootTransform");
  89. //::strcpy (Name, "Default");
  90. Name[0] = 0;
  91. return ;
  92. }
  93. /***********************************************************************************************
  94. * HTreeClass::~HTreeClass -- destructor *
  95. * *
  96. * INPUT: *
  97. * *
  98. * OUTPUT: *
  99. * *
  100. * WARNINGS: *
  101. * *
  102. * HISTORY: *
  103. * 08/11/1997 GH : Created. *
  104. *=============================================================================================*/
  105. HTreeClass::~HTreeClass(void)
  106. {
  107. Free();
  108. }
  109. /***********************************************************************************************
  110. * HTreeClass::HTreeClass -- copy constructor *
  111. * *
  112. * INPUT: *
  113. * *
  114. * OUTPUT: *
  115. * *
  116. * WARNINGS: *
  117. * *
  118. * HISTORY: *
  119. * 3/4/98 GTH : Created. *
  120. *=============================================================================================*/
  121. HTreeClass::HTreeClass(const HTreeClass & src) :
  122. NumPivots(0),
  123. Pivot(NULL),
  124. ScaleFactor(1.0f)
  125. {
  126. memcpy(&Name,&src.Name,sizeof(Name));
  127. NumPivots = src.NumPivots;
  128. if (NumPivots > 0) {
  129. Pivot = new PivotClass[NumPivots];
  130. }
  131. for (int pi = 0; pi < NumPivots; pi++) {
  132. Pivot[pi] = src.Pivot[pi];
  133. if (src.Pivot[pi].Parent != NULL) {
  134. Pivot[pi].Parent = &(Pivot[src.Pivot[pi].Parent->Index]);
  135. } else {
  136. Pivot[pi].Parent = NULL;
  137. }
  138. }
  139. ScaleFactor = src.ScaleFactor;
  140. }
  141. /***********************************************************************************************
  142. * HTreeClass::Load -- loads a hierarchy tree from a file *
  143. * *
  144. * INPUT: *
  145. * *
  146. * OUTPUT: *
  147. * *
  148. * WARNINGS: *
  149. * *
  150. * HISTORY: *
  151. * 08/11/1997 GH : Created. *
  152. *=============================================================================================*/
  153. int HTreeClass::Load_W3D(ChunkLoadClass & cload)
  154. {
  155. Free();
  156. /*
  157. ** Read the first chunk, it should be the hierarchy header
  158. */
  159. if (!cload.Open_Chunk()) return LOAD_ERROR;
  160. if (cload.Cur_Chunk_ID() != W3D_CHUNK_HIERARCHY_HEADER) {
  161. // ERROR: Expected Hierarchy Header
  162. return LOAD_ERROR;
  163. }
  164. W3dHierarchyStruct header;
  165. if (cload.Read(&header,sizeof(W3dHierarchyStruct)) != sizeof(W3dHierarchyStruct)) {
  166. return LOAD_ERROR;
  167. }
  168. cload.Close_Chunk();
  169. /*
  170. ** Check the version, if < 3.0 add a root node for everything
  171. ** to attach to. The load_pivots function will also have to be
  172. ** notified of this.
  173. */
  174. bool pre30 = false;
  175. if (header.Version < W3D_MAKE_VERSION(3,0)) {
  176. header.NumPivots ++;
  177. pre30 = true;
  178. }
  179. /*
  180. ** Allocate the array of pivots
  181. */
  182. memcpy(Name,header.Name,W3D_NAME_LEN);
  183. NumPivots = header.NumPivots;
  184. if (NumPivots > 0) {
  185. Pivot = new PivotClass[NumPivots];
  186. }
  187. /*
  188. ** Now, read in all of the other chunks for this hierarchy.
  189. */
  190. while (cload.Open_Chunk()) {
  191. switch (cload.Cur_Chunk_ID()) {
  192. case W3D_CHUNK_PIVOTS:
  193. if (!read_pivots(cload,pre30)) {
  194. goto Error;
  195. }
  196. break;
  197. default:
  198. // ERROR: expected W3D_CHUNK_PIVOTS!
  199. break;
  200. }
  201. cload.Close_Chunk();
  202. }
  203. return OK;
  204. Error:
  205. Free();
  206. return LOAD_ERROR;
  207. }
  208. /***********************************************************************************************
  209. * HTreeClass::read_pivots -- reads the pivots out of a file *
  210. * *
  211. * INPUT: *
  212. * *
  213. * OUTPUT: *
  214. * *
  215. * WARNINGS: *
  216. * *
  217. * HISTORY: *
  218. * 08/11/1997 GH : Created. *
  219. *=============================================================================================*/
  220. bool HTreeClass::read_pivots(ChunkLoadClass & cload,bool pre30)
  221. {
  222. W3dPivotStruct piv;
  223. int first_piv = 0;
  224. /*
  225. ** At (w3d file format) version 3.0, I added a node for the root. Pre-3.0 htrees didn't have
  226. ** this so we just put one in.
  227. */
  228. if (pre30) {
  229. Pivot[0].Index = 0;
  230. Pivot[0].Parent = NULL;
  231. Pivot[0].BaseTransform.Make_Identity();
  232. Pivot[0].Transform.Make_Identity();
  233. Pivot[0].IsVisible = true;
  234. strcpy(Pivot[0].Name,"RootTransform");
  235. first_piv++;
  236. }
  237. for (int pidx=first_piv; pidx < NumPivots; pidx++) {
  238. if (cload.Read(&piv,sizeof(W3dPivotStruct)) != sizeof(W3dPivotStruct)) {
  239. return false;
  240. }
  241. memcpy(Pivot[pidx].Name,piv.Name,W3D_NAME_LEN);
  242. Pivot[pidx].Index = pidx;
  243. Pivot[pidx].BaseTransform.Make_Identity();
  244. Pivot[pidx].BaseTransform.Translate(Vector3(piv.Translation.X,piv.Translation.Y,piv.Translation.Z));
  245. Pivot[pidx].BaseTransform =
  246. Pivot[pidx].BaseTransform *
  247. Build_Matrix3D(
  248. Quaternion(
  249. piv.Rotation.Q[0],
  250. piv.Rotation.Q[1],
  251. piv.Rotation.Q[2],
  252. piv.Rotation.Q[3]
  253. )
  254. );
  255. /*
  256. ** At version 3.0 a root node was added, this "fixes up" pre-3.0 files
  257. ** to have that root node
  258. */
  259. if (pre30) {
  260. piv.ParentIdx += 1;
  261. }
  262. /*
  263. ** Set the parent pointer. The first pivot will have a parent index
  264. ** of -1 (in post-3.0 files) so set its parent to NULL.
  265. */
  266. if (piv.ParentIdx == -1) {
  267. Pivot[pidx].Parent = NULL;
  268. assert(pidx == 0);
  269. } else {
  270. Pivot[pidx].Parent = &(Pivot[piv.ParentIdx]);
  271. }
  272. }
  273. Pivot[0].Transform.Make_Identity();
  274. Pivot[0].IsVisible = true;
  275. return true;
  276. }
  277. /***********************************************************************************************
  278. * HTreeClass::Free -- de-allocate all memory in use *
  279. * *
  280. * INPUT: *
  281. * *
  282. * OUTPUT: *
  283. * *
  284. * WARNINGS: *
  285. * *
  286. * HISTORY: *
  287. * 08/11/1997 GH : Created. *
  288. *=============================================================================================*/
  289. void HTreeClass::Free(void)
  290. {
  291. if (Pivot != NULL) {
  292. delete[] Pivot;
  293. Pivot = NULL;
  294. }
  295. NumPivots = 0;
  296. // Also clean up other members:
  297. ScaleFactor = 1.0f;
  298. }
  299. /***********************************************************************************************
  300. * HTreeClass::Simple_Evaluate_Pivot -- Returns the transform of a pivot at the given frame. *
  301. * *
  302. * INPUT: *
  303. * *
  304. * OUTPUT: *
  305. * *
  306. * WARNINGS: *
  307. * *
  308. * HISTORY: *
  309. * 04/13/2000 PDS : Created. *
  310. *=============================================================================================*/
  311. bool HTreeClass::Simple_Evaluate_Pivot
  312. (
  313. HAnimClass * motion,
  314. int pivot_index,
  315. float frame,
  316. const Matrix3D & obj_tm,
  317. Matrix3D * end_tm
  318. ) const
  319. {
  320. bool retval = false;
  321. end_tm->Make_Identity ();
  322. if ( motion != NULL &&
  323. end_tm != NULL &&
  324. pivot_index >= 0 &&
  325. pivot_index < NumPivots)
  326. {
  327. //
  328. // Loop over the hierarchy of pivots that this pivot is
  329. // attached to and transform each.
  330. //
  331. for ( PivotClass *pivot = &Pivot[pivot_index];
  332. pivot != NULL && pivot->Parent != NULL;
  333. pivot = pivot->Parent)
  334. {
  335. //
  336. // Build a matrix that represents the animation for this pivot
  337. //
  338. Matrix3D anim_tm;
  339. motion->Get_Transform(anim_tm, pivot->Index, frame);
  340. // Quaternion q;
  341. // motion->Get_Orientation (q, pivot->Index, frame);
  342. // Matrix3D anim_tm = ::Build_Matrix3D(q);
  343. Vector3 trans;
  344. anim_tm.Get_Translation (&trans);
  345. anim_tm.Set_Translation (trans * ScaleFactor);
  346. //
  347. // Transform the animation transform by the 'relative-to-parent' transform.
  348. //
  349. Matrix3D curr_tm;
  350. Matrix3D::Multiply (pivot->BaseTransform, anim_tm, &curr_tm);
  351. //
  352. // Transform the return value by this transform
  353. //
  354. Matrix3D::Multiply (curr_tm, *end_tm, end_tm);
  355. }
  356. //
  357. // Transform the return value by the object's transform
  358. //
  359. Matrix3D::Multiply (obj_tm, *end_tm, end_tm);
  360. // Success!
  361. retval = true;
  362. }
  363. return retval;
  364. }
  365. /***********************************************************************************************
  366. * HTreeClass::Simple_Evaluate_Pivot -- Returns the transform of a pivot at the given frame. *
  367. * *
  368. * INPUT: *
  369. * *
  370. * OUTPUT: *
  371. * *
  372. * WARNINGS: *
  373. * *
  374. * HISTORY: *
  375. * 04/13/2000 PDS : Created. *
  376. *=============================================================================================*/
  377. bool HTreeClass::Simple_Evaluate_Pivot
  378. (
  379. int pivot_index,
  380. const Matrix3D & obj_tm,
  381. Matrix3D * end_tm
  382. ) const
  383. {
  384. bool retval = false;
  385. end_tm->Make_Identity ();
  386. if ( end_tm != NULL &&
  387. pivot_index >= 0 &&
  388. pivot_index < NumPivots)
  389. {
  390. //
  391. // Loop over the hierarchy of pivots that this pivot is
  392. // attached to and transform each.
  393. //
  394. for ( PivotClass *pivot = &Pivot[pivot_index];
  395. pivot != NULL && pivot->Parent != NULL;
  396. pivot = pivot->Parent)
  397. {
  398. //
  399. // Build a matrix that represents the animation for this pivot
  400. //
  401. Matrix3D anim_tm (1);
  402. //
  403. // Transform the animation transform by the 'relative-to-parent' transform.
  404. //
  405. Matrix3D curr_tm;
  406. Matrix3D::Multiply (pivot->BaseTransform, anim_tm, &curr_tm);
  407. //
  408. // Transform the return value by this transform
  409. //
  410. Matrix3D::Multiply (curr_tm, *end_tm, end_tm);
  411. }
  412. //
  413. // Transform the return value by the object's transform
  414. //
  415. Matrix3D::Multiply (obj_tm, *end_tm, end_tm);
  416. retval = true;
  417. }
  418. return retval;
  419. }
  420. /***********************************************************************************************
  421. * HTreeClass::Base_Update -- Computes the base pose transform for each pivot *
  422. * *
  423. * INPUT: *
  424. * *
  425. * OUTPUT: *
  426. * *
  427. * WARNINGS: *
  428. * *
  429. * HISTORY: *
  430. * 08/11/1997 GH : Created. *
  431. *=============================================================================================*/
  432. void HTreeClass::Base_Update(const Matrix3D & root)
  433. {
  434. PivotClass *pivot;
  435. Pivot[0].Transform = root;
  436. Pivot[0].IsVisible = true;
  437. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  438. pivot = &Pivot[piv_idx];
  439. assert(pivot->Parent != NULL);
  440. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  441. pivot->IsVisible = 1;
  442. if (pivot->IsCaptured) pivot->Capture_Update();
  443. }
  444. }
  445. /***********************************************************************************************
  446. * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
  447. * *
  448. * INPUT: *
  449. * *
  450. * OUTPUT: *
  451. * *
  452. * WARNINGS: *
  453. * *
  454. * HISTORY: *
  455. * 08/11/1997 GH : Created. *
  456. *=============================================================================================*/
  457. void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float frame)
  458. {
  459. PivotClass *pivot;
  460. Pivot[0].Transform = root;
  461. Pivot[0].IsVisible = true;
  462. int num_anim_pivots = motion->Get_Num_Pivots ();
  463. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  464. pivot = &Pivot[piv_idx];
  465. // base pose
  466. assert(pivot->Parent != NULL);
  467. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  468. // Don't update this pivot if the HTree doesn't have animation data for it...
  469. if (piv_idx < num_anim_pivots) {
  470. // animation
  471. Vector3 trans;
  472. motion->Get_Translation(trans,piv_idx,frame);
  473. pivot->Transform.Translate(trans * ScaleFactor);
  474. Quaternion q;
  475. motion->Get_Orientation(q,piv_idx,frame);
  476. Matrix3D mtx=::Build_Matrix3D(q);
  477. pivot->Transform = pivot->Transform * mtx;
  478. // visibility
  479. pivot->IsVisible = motion->Get_Visibility(piv_idx,frame);
  480. }
  481. if (pivot->IsCaptured) {
  482. pivot->Capture_Update();
  483. pivot->IsVisible = true;
  484. }
  485. }
  486. }
  487. /***********************************************************************************************
  488. * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
  489. * *
  490. * INPUT: *
  491. * *
  492. * OUTPUT: *
  493. * *
  494. * WARNINGS: *
  495. * *
  496. * HISTORY: *
  497. * 3/4/98 GTH : Created. *
  498. *=============================================================================================*/
  499. void HTreeClass::Blend_Update
  500. (
  501. const Matrix3D & root,
  502. HAnimClass * motion0,
  503. float frame0,
  504. HAnimClass * motion1,
  505. float frame1,
  506. float percentage // 0.0 = motion0. 1.0 = motion1
  507. )
  508. {
  509. PivotClass *pivot;
  510. Pivot[0].Transform = root;
  511. Pivot[0].IsVisible = true;
  512. int num_anim_pivots = MIN( motion0->Get_Num_Pivots (), motion1->Get_Num_Pivots () );
  513. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  514. pivot = &Pivot[piv_idx];
  515. assert(pivot->Parent != NULL);
  516. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  517. if (piv_idx < num_anim_pivots) {
  518. // interpolated translation
  519. Vector3 trans0;
  520. motion0->Get_Translation(trans0,piv_idx,frame0);
  521. Vector3 trans1;
  522. motion1->Get_Translation(trans1,piv_idx,frame1);
  523. Vector3 lerped = (1.0 - percentage) * trans0 + (percentage) * trans1;
  524. pivot->Transform.Translate(lerped * ScaleFactor);
  525. // interpolated rotation
  526. Quaternion q0;
  527. motion0->Get_Orientation(q0,piv_idx,frame0);
  528. Quaternion q1;
  529. motion1->Get_Orientation(q1,piv_idx,frame1);
  530. Quaternion q;
  531. Fast_Slerp(q,q0,q1,percentage);
  532. pivot->Transform = pivot->Transform * Build_Matrix3D(q);
  533. pivot->IsVisible = (motion0->Get_Visibility(piv_idx,frame0) || motion1->Get_Visibility(piv_idx,frame1));
  534. }
  535. if (pivot->IsCaptured) {
  536. pivot->Capture_Update();
  537. pivot->IsVisible = true;
  538. }
  539. }
  540. }
  541. /***********************************************************************************************
  542. * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
  543. * *
  544. * INPUT: *
  545. * *
  546. * OUTPUT: *
  547. * *
  548. * WARNINGS: *
  549. * *
  550. * HISTORY: *
  551. * 3/4/98 GTH : Created. *
  552. *=============================================================================================*/
  553. void HTreeClass::Combo_Update
  554. (
  555. const Matrix3D & root,
  556. HAnimComboClass *anim
  557. )
  558. {
  559. PivotClass *pivot;
  560. Pivot[0].Transform = root;
  561. Pivot[0].IsVisible = true;
  562. int num_anim_pivots = 100000;
  563. for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
  564. num_anim_pivots = MIN( num_anim_pivots, anim->Peek_Motion( anim_num )->Get_Num_Pivots() );
  565. }
  566. if ( num_anim_pivots == 100000 ) {
  567. num_anim_pivots = 0;
  568. }
  569. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  570. pivot = &Pivot[piv_idx];
  571. assert(pivot->Parent != NULL);
  572. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  573. if (piv_idx < num_anim_pivots) {
  574. #define ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  575. Vector3 trans(0,0,0);
  576. Quaternion q0;
  577. Quaternion q1;
  578. #ifndef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  579. float last_weight = 0;
  580. #endif
  581. float weight_total = 0;
  582. int wcount = 0;
  583. for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
  584. HAnimClass *motion = anim->Get_Motion( anim_num );
  585. if ( motion != NULL ) {
  586. float frame_num = anim->Get_Frame( anim_num );
  587. PivotMapClass * pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
  588. //float *pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
  589. float weight = anim->Get_Weight( anim_num );
  590. if ( pivot_map != NULL ) {
  591. weight *= (*pivot_map)[piv_idx];
  592. // GREG - Pivot maps are ref counted so shouldn't we
  593. // release the rivot map here?
  594. pivot_map->Release_Ref();
  595. }
  596. if ( weight != 0.0 ) {
  597. wcount++;
  598. Vector3 temp_trans;
  599. motion->Get_Translation( temp_trans, piv_idx, frame_num );
  600. trans += weight * ScaleFactor * temp_trans;
  601. weight_total += weight;
  602. #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  603. motion->Get_Orientation(q1,piv_idx, frame_num );
  604. if ( wcount == 1 ) {
  605. q0 = q1;
  606. } else {
  607. Fast_Slerp(q0, q0, q1, weight / weight_total );
  608. }
  609. #else
  610. q0 = q1;
  611. motion->Get_Orientation(q1, piv_idx, frame_num );
  612. last_weight = weight;
  613. #endif
  614. }
  615. motion->Release_Ref();
  616. }
  617. }
  618. #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  619. if (weight_total != 0.0f ) {
  620. // SKB: Removed assert because I have a case where I don't want normalization.
  621. // One anim moves X, the other moves Y. Assert was just in to warn programmers.
  622. // WWASSERT(WWMath::Fabs( weight_total - 1.0 ) < WWMATH_EPSILON);
  623. pivot->Transform.Translate(trans);
  624. pivot->Transform = pivot->Transform * Build_Matrix3D(q0);
  625. }
  626. #else
  627. if (( weight_total != 0.0f ) && (wcount >= 2)) {
  628. pivot->Transform.Translate( trans / weight_total );
  629. Quaternion q = Slerp_( q0, q1, last_weight / weight_total );
  630. pivot->Transform = pivot->Transform * Build_Matrix3D(q);
  631. } else if (weight_total != 0.0f) {
  632. pivot->Transform.Translate( trans / weight_total );
  633. pivot->Transform = pivot->Transform * Build_Matrix3D(q1);
  634. }
  635. #endif
  636. pivot->IsVisible = false;
  637. for ( anim_num = 0; (anim_num < anim->Get_Num_Anims()) && (!pivot->IsVisible); anim_num++ ) {
  638. HAnimClass *motion = anim->Get_Motion( anim_num );
  639. if ( motion != NULL ) {
  640. float frame_num = anim->Get_Frame( anim_num );
  641. pivot->IsVisible |= motion->Get_Visibility(piv_idx,frame_num);
  642. motion->Release_Ref();
  643. }
  644. }
  645. }
  646. if (pivot->IsCaptured) {
  647. pivot->Capture_Update();
  648. pivot->IsVisible = true;
  649. }
  650. }
  651. }
  652. /***********************************************************************************************
  653. * HTreeClass::Find_Bone -- Find a bone by name *
  654. * *
  655. * INPUT: *
  656. * *
  657. * OUTPUT: *
  658. * *
  659. * WARNINGS: *
  660. * *
  661. * HISTORY: *
  662. * 11/4/97 GTH : Created. *
  663. *=============================================================================================*/
  664. int HTreeClass::Get_Bone_Index(const char * name) const
  665. {
  666. for (int i=0; i < NumPivots; i++) {
  667. if (stricmp(Pivot[i].Name,name) == 0) {
  668. return i;
  669. }
  670. }
  671. return 0;
  672. }
  673. /***********************************************************************************************
  674. * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
  675. * *
  676. * INPUT: *
  677. * *
  678. * OUTPUT: *
  679. * *
  680. * WARNINGS: *
  681. * *
  682. * HISTORY: *
  683. * 11/4/97 GTH : Created. *
  684. *=============================================================================================*/
  685. const char * HTreeClass::Get_Bone_Name(int boneidx) const
  686. {
  687. assert(boneidx >= 0);
  688. assert(boneidx < NumPivots);
  689. return Pivot[boneidx].Name;
  690. }
  691. /***********************************************************************************************
  692. * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
  693. * *
  694. * INPUT: *
  695. * boneidx - the bone you are interested in *
  696. * *
  697. * OUTPUT: *
  698. * the index of that bone's parent *
  699. * *
  700. * WARNINGS: *
  701. * *
  702. * HISTORY: *
  703. * 4/12/2000 gth : Created. *
  704. *=============================================================================================*/
  705. int HTreeClass::Get_Parent_Index(int boneidx) const
  706. {
  707. assert(boneidx >= 0);
  708. assert(boneidx < NumPivots);
  709. if (Pivot[boneidx].Parent != NULL) {
  710. return Pivot[boneidx].Parent->Index;
  711. } else {
  712. return 0;
  713. }
  714. }
  715. // Scale this HTree by a constant factor:
  716. void HTreeClass::Scale(float factor)
  717. {
  718. if (factor == 1.0f) return;
  719. // Scale pivot translations
  720. for (int i = 0; i < NumPivots; i++) {
  721. Matrix3D &pivot_transform = Pivot[i].BaseTransform;
  722. Vector3 pivot_translation;
  723. pivot_transform.Get_Translation(&pivot_translation);
  724. pivot_translation *= factor;
  725. pivot_transform.Set_Translation(pivot_translation);
  726. }
  727. // Set state used later to scale animations:
  728. ScaleFactor *= factor;
  729. }
  730. void HTreeClass::Capture_Bone(int boneindex)
  731. {
  732. assert(boneindex >= 0);
  733. assert(boneindex < NumPivots);
  734. Pivot[boneindex].IsCaptured = true;
  735. }
  736. void HTreeClass::Release_Bone(int boneindex)
  737. {
  738. assert(boneindex >= 0);
  739. assert(boneindex < NumPivots);
  740. Pivot[boneindex].IsCaptured = false;
  741. }
  742. bool HTreeClass::Is_Bone_Captured(int boneindex) const
  743. {
  744. assert(boneindex >= 0);
  745. assert(boneindex < NumPivots);
  746. return Pivot[boneindex].IsCaptured;
  747. }
  748. void HTreeClass::Control_Bone(int boneindex,const Matrix3D & relative_tm,bool world_space_translation)
  749. {
  750. assert(boneindex >= 0);
  751. assert(boneindex < NumPivots);
  752. assert(Pivot[boneindex].IsCaptured);
  753. Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
  754. Pivot[boneindex].CapTransform = relative_tm;
  755. }
  756. void HTreeClass::Get_Bone_Control(int boneindex, Matrix3D & relative_tm) const
  757. {
  758. assert(boneindex >= 0);
  759. assert(boneindex < NumPivots);
  760. //
  761. // Return the bone's control transform to the caller
  762. //
  763. if (Pivot[boneindex].IsCaptured) {
  764. relative_tm = Pivot[boneindex].CapTransform;
  765. } else {
  766. relative_tm.Make_Identity ();
  767. }
  768. return ;
  769. }
  770. // Morph the bones on the HTree using weights from a number of other HTrees
  771. HTreeClass * HTreeClass::Create_Morphed( int num_morph_sources,
  772. const float morph_weights[],
  773. const HTreeClass *tree_array[] )
  774. {
  775. int i;
  776. assert(num_morph_sources>0);
  777. for(i=0;i<num_morph_sources;i++) {
  778. assert( tree_array[i] );
  779. assert( morph_weights[i]>=0.0f && morph_weights[i]<=1.0f );
  780. }
  781. for(i=0;i<num_morph_sources-1;i++) {
  782. assert( tree_array[i]->NumPivots == tree_array[i+1]->NumPivots );
  783. }
  784. // Clone the first one,
  785. HTreeClass * new_tree = new HTreeClass( *tree_array[0] );
  786. // Then interpolate all the pivots translations
  787. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  788. Vector3 pos(0.0f,0.0f,0.0f);
  789. for(int nm = 0; nm < num_morph_sources; nm++) {
  790. pos.X += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().X*morph_weights[nm];
  791. pos.Y += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Y*morph_weights[nm];
  792. pos.Z += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Z*morph_weights[nm];
  793. }
  794. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  795. }
  796. return new_tree;
  797. }
  798. // Create an HTree by Interpolating between others
  799. HTreeClass * HTreeClass::Create_Interpolated( const HTreeClass * tree_a0_b0,
  800. const HTreeClass * tree_a0_b1,
  801. const HTreeClass * tree_a1_b0,
  802. const HTreeClass * tree_a1_b1,
  803. float lerp_a, float lerp_b )
  804. {
  805. assert( tree_a0_b0->NumPivots == tree_a0_b1->NumPivots );
  806. assert( tree_a0_b0->NumPivots == tree_a1_b0->NumPivots );
  807. assert( tree_a0_b0->NumPivots == tree_a1_b1->NumPivots );
  808. // Clone the first one,
  809. HTreeClass * new_tree = new HTreeClass( *tree_a0_b0 );
  810. // Then interpolate all the pivots translations
  811. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  812. Vector3 pos_a0 = Lerp( tree_a0_b0->Pivot[pi].BaseTransform.Get_Translation(),
  813. tree_a0_b1->Pivot[pi].BaseTransform.Get_Translation(),
  814. lerp_b );
  815. Vector3 pos_a1 = Lerp( tree_a1_b0->Pivot[pi].BaseTransform.Get_Translation(),
  816. tree_a1_b1->Pivot[pi].BaseTransform.Get_Translation(),
  817. lerp_b );
  818. Vector3 pos = Lerp( pos_a0, pos_a1, lerp_a );
  819. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  820. }
  821. return new_tree;
  822. }
  823. // Create an HTree by Interpolating between others
  824. HTreeClass * HTreeClass::Create_Interpolated(const HTreeClass * tree_base,
  825. const HTreeClass * tree_a,
  826. const HTreeClass * tree_b,
  827. float a_scale, float b_scale )
  828. {
  829. WWMEMLOG(MEM_ANIMATION);
  830. assert( tree_base->NumPivots == tree_a->NumPivots );
  831. assert( tree_base->NumPivots == tree_b->NumPivots );
  832. // Clone the first one,
  833. HTreeClass * new_tree = new HTreeClass( *tree_base );
  834. float a_scale_abs = WWMath::Fabs( a_scale );
  835. float b_scale_abs = WWMath::Fabs( b_scale );
  836. if ( a_scale_abs + b_scale_abs > 0 ) {
  837. // Then interpolate all the pivots translations
  838. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  839. Vector3 pos_a = Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
  840. tree_a->Pivot[pi].BaseTransform.Get_Translation(),
  841. a_scale );
  842. Vector3 pos_b = Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
  843. tree_b->Pivot[pi].BaseTransform.Get_Translation(),
  844. b_scale );
  845. Vector3 pos = (pos_a * a_scale_abs + pos_b * b_scale_abs ) / ( a_scale_abs + b_scale_abs );
  846. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  847. }
  848. }
  849. return new_tree;
  850. }