htree.cpp 45 KB

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