htree.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  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: /VSS_Sync/ww3d2/htree.cpp 11 8/29/01 9:49p Vss_sync $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G 3D Library *
  24. * *
  25. * $Archive:: /VSS_Sync/ww3d2/htree.cpp $*
  26. * *
  27. * Author:: Greg_h *
  28. * *
  29. * $Modtime:: 8/29/01 8:36p $*
  30. * *
  31. * $Revision:: 11 $*
  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::Base_Update -- Computes the base pose transform for each pivot *
  393. * *
  394. * INPUT: *
  395. * *
  396. * OUTPUT: *
  397. * *
  398. * WARNINGS: *
  399. * *
  400. * HISTORY: *
  401. * 08/11/1997 GH : Created. *
  402. *=============================================================================================*/
  403. void HTreeClass::Base_Update(const Matrix3D & root)
  404. {
  405. PivotClass *pivot;
  406. Pivot[0].Transform = root;
  407. Pivot[0].IsVisible = true;
  408. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  409. pivot = &Pivot[piv_idx];
  410. assert(pivot->Parent != NULL);
  411. Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
  412. pivot->IsVisible = 1;
  413. if (pivot->Is_Captured()) pivot->Capture_Update();
  414. }
  415. }
  416. /***********************************************************************************************
  417. * HTreeClass::Anim_Update -- Computes the transform for each pivot with motion *
  418. * *
  419. * INPUT: *
  420. * *
  421. * OUTPUT: *
  422. * *
  423. * WARNINGS: *
  424. * *
  425. * HISTORY: *
  426. * 08/11/1997 GH : Created. *
  427. *=============================================================================================*/
  428. void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float frame)
  429. {
  430. PivotClass *pivot;
  431. Matrix3D mtx;
  432. Pivot[0].Transform = root;
  433. Pivot[0].IsVisible = true;
  434. int num_anim_pivots = motion->Get_Num_Pivots ();
  435. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  436. pivot = &Pivot[piv_idx];
  437. // base pose
  438. assert(pivot->Parent != NULL);
  439. Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
  440. // Don't update this pivot if the HTree doesn't have animation data for it...
  441. if (piv_idx < num_anim_pivots) {
  442. // animation
  443. Vector3 trans;
  444. motion->Get_Translation(trans,piv_idx,frame);
  445. pivot->Transform.Translate(trans * ScaleFactor);
  446. Quaternion q;
  447. motion->Get_Orientation(q,piv_idx,frame);
  448. ::Build_Matrix3D(q,mtx);
  449. #ifdef ALLOW_TEMPORARIES
  450. pivot->Transform = pivot->Transform * mtx;
  451. #else
  452. pivot->Transform.postMul(mtx);
  453. #endif
  454. // visibility
  455. pivot->IsVisible = motion->Get_Visibility(piv_idx,frame);
  456. }
  457. if (pivot->Is_Captured())
  458. {
  459. pivot->Capture_Update();
  460. pivot->IsVisible = true;
  461. }
  462. }
  463. }
  464. /*Customized version of the above which excludes interpolation and assumes HRawAnimClass
  465. For use by 'Generals' -MW*/
  466. void HTreeClass::Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame)
  467. {
  468. PivotClass *pivot,*endpivot,*lastAnimPivot;
  469. Pivot[0].Transform = root;
  470. Pivot[0].IsVisible = true;
  471. int num_anim_pivots = motion->Get_Num_Pivots ();
  472. //Get integer frame
  473. int iframe=WWMath::Float_To_Long(frame);
  474. if (iframe >= motion->Get_Num_Frames())
  475. iframe = 0;
  476. Vector3 trans;
  477. Quaternion q;
  478. Matrix3D mtx;
  479. struct NodeMotionStruct * nodeMotion = ((HRawAnimClass*)motion)->Get_Node_Motion_Array();
  480. nodeMotion += 1; //skip the root node
  481. pivot = &Pivot[1];
  482. endpivot=pivot+(NumPivots-1);
  483. lastAnimPivot = &Pivot[num_anim_pivots];
  484. for (int piv_idx=1; pivot < endpivot; pivot++,nodeMotion++) {
  485. // base pose
  486. assert(pivot->Parent != NULL);
  487. Matrix3D::Multiply(pivot->Parent->Transform, pivot->BaseTransform, &(pivot->Transform));
  488. // Don't update this pivot if the HTree doesn't have animation data for it...
  489. if (pivot < lastAnimPivot)
  490. {
  491. // animation
  492. trans.Set(0.0f,0.0f,0.0f);
  493. Matrix3D *xform=&pivot->Transform;
  494. if (nodeMotion->X != NULL)
  495. nodeMotion->X->Get_Vector(iframe,&(trans[0]));
  496. if (nodeMotion->Y != NULL)
  497. nodeMotion->Y->Get_Vector(iframe,&(trans[1]));
  498. if (nodeMotion->Z != NULL)
  499. nodeMotion->Z->Get_Vector(iframe,&(trans[2]));
  500. if (ScaleFactor == 1.0f)
  501. xform->Translate(trans);
  502. else
  503. xform->Translate(trans*ScaleFactor);
  504. if (nodeMotion->Q != NULL)
  505. { nodeMotion->Q->Get_Vector_As_Quat(iframe, q);
  506. #ifdef ALLOW_TEMPORARIES
  507. *xform = *xform * ::Build_Matrix3D(q,mtx);
  508. #else
  509. xform->postMul(::Build_Matrix3D(q,mtx));
  510. #endif
  511. }
  512. // visibility
  513. if (nodeMotion->Vis != NULL)
  514. pivot->IsVisible=(nodeMotion->Vis->Get_Bit(iframe) == 1);
  515. else
  516. pivot->IsVisible=1;
  517. }
  518. if (pivot->Is_Captured())
  519. {
  520. pivot->Capture_Update();
  521. pivot->IsVisible = true;
  522. }
  523. }
  524. }
  525. /***********************************************************************************************
  526. * HTreeClass::Blend_Update -- computes each pivot as a blend of two anims *
  527. * *
  528. * INPUT: *
  529. * *
  530. * OUTPUT: *
  531. * *
  532. * WARNINGS: *
  533. * *
  534. * HISTORY: *
  535. * 3/4/98 GTH : Created. *
  536. *=============================================================================================*/
  537. void HTreeClass::Blend_Update
  538. (
  539. const Matrix3D & root,
  540. HAnimClass * motion0,
  541. float frame0,
  542. HAnimClass * motion1,
  543. float frame1,
  544. float percentage // 0.0 = motion0. 1.0 = motion1
  545. )
  546. {
  547. PivotClass *pivot;
  548. Matrix3D mtx;
  549. Pivot[0].Transform = root;
  550. Pivot[0].IsVisible = true;
  551. int num_anim_pivots = MIN( motion0->Get_Num_Pivots (), motion1->Get_Num_Pivots () );
  552. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  553. pivot = &Pivot[piv_idx];
  554. assert(pivot->Parent != NULL);
  555. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  556. if (piv_idx < num_anim_pivots) {
  557. // interpolated translation
  558. Vector3 trans0;
  559. motion0->Get_Translation(trans0,piv_idx,frame0);
  560. Vector3 trans1;
  561. motion1->Get_Translation(trans1,piv_idx,frame1);
  562. Vector3 lerped = (1.0 - percentage) * trans0 + (percentage) * trans1;
  563. pivot->Transform.Translate(lerped * ScaleFactor);
  564. // interpolated rotation
  565. Quaternion q0;
  566. motion0->Get_Orientation(q0,piv_idx,frame0);
  567. Quaternion q1;
  568. motion1->Get_Orientation(q1,piv_idx,frame1);
  569. Quaternion q;
  570. Fast_Slerp(q,q0,q1,percentage);
  571. #ifdef ALLOW_TEMPORARIES
  572. pivot->Transform = pivot->Transform * Build_Matrix3D(q);
  573. #else
  574. pivot->Transform.postMul(Build_Matrix3D(q,mtx));
  575. #endif
  576. pivot->IsVisible = (motion0->Get_Visibility(piv_idx,frame0) || motion1->Get_Visibility(piv_idx,frame1));
  577. }
  578. if (pivot->Is_Captured())
  579. {
  580. pivot->Capture_Update();
  581. pivot->IsVisible = true;
  582. }
  583. }
  584. }
  585. /***********************************************************************************************
  586. * HTreeClass::Combo_Update -- compute each pivot's transform using an anim combo *
  587. * *
  588. * INPUT: *
  589. * *
  590. * OUTPUT: *
  591. * *
  592. * WARNINGS: *
  593. * *
  594. * HISTORY: *
  595. * 3/4/98 GTH : Created. *
  596. *=============================================================================================*/
  597. void HTreeClass::Combo_Update
  598. (
  599. const Matrix3D & root,
  600. HAnimComboClass *anim
  601. )
  602. {
  603. PivotClass *pivot;
  604. Matrix3D mtx;
  605. Pivot[0].Transform = root;
  606. Pivot[0].IsVisible = true;
  607. int num_anim_pivots = 100000;
  608. for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
  609. num_anim_pivots = MIN( num_anim_pivots, anim->Peek_Motion( anim_num )->Get_Num_Pivots() );
  610. }
  611. if ( num_anim_pivots == 100000 ) {
  612. num_anim_pivots = 0;
  613. }
  614. for (int piv_idx=1; piv_idx < NumPivots; piv_idx++) {
  615. pivot = &Pivot[piv_idx];
  616. assert(pivot->Parent != NULL);
  617. Matrix3D::Multiply(pivot->Parent->Transform,pivot->BaseTransform,&(pivot->Transform));
  618. if (piv_idx < num_anim_pivots) {
  619. #define ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  620. Vector3 trans(0,0,0);
  621. Quaternion q0;
  622. Quaternion q1;
  623. #ifndef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  624. float last_weight = 0;
  625. #endif
  626. float weight_total = 0;
  627. int wcount = 0;
  628. for ( int anim_num = 0; anim_num < anim->Get_Num_Anims(); anim_num++ ) {
  629. HAnimClass *motion = anim->Get_Motion( anim_num );
  630. if ( motion != NULL ) {
  631. float frame_num = anim->Get_Frame( anim_num );
  632. PivotMapClass * pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
  633. //float *pivot_map = anim->Get_Pivot_Weight_Map( anim_num );
  634. float weight = anim->Get_Weight( anim_num );
  635. if ( pivot_map != NULL ) {
  636. weight *= (*pivot_map)[piv_idx];
  637. // GREG - Pivot maps are ref counted so shouldn't we
  638. // release the rivot map here?
  639. pivot_map->Release_Ref();
  640. }
  641. if ( weight != 0.0 ) {
  642. wcount++;
  643. Vector3 temp_trans;
  644. motion->Get_Translation( temp_trans, piv_idx, frame_num );
  645. trans += weight * ScaleFactor * temp_trans;
  646. weight_total += weight;
  647. #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  648. motion->Get_Orientation(q1,piv_idx, frame_num );
  649. if ( wcount == 1 ) {
  650. q0 = q1;
  651. } else {
  652. Fast_Slerp(q0, q0, q1, weight / weight_total );
  653. }
  654. #else
  655. q0 = q1;
  656. motion->Get_Orientation(q1, piv_idx, frame_num );
  657. last_weight = weight;
  658. #endif
  659. }
  660. motion->Release_Ref();
  661. }
  662. }
  663. #ifdef ASSUME_NORMALIZED_ANIM_COMBO_WEIGHTS
  664. if (weight_total != 0.0f ) {
  665. // SKB: Removed assert because I have a case where I don't want normalization.
  666. // One anim moves X, the other moves Y. Assert was just in to warn programmers.
  667. // WWASSERT(WWMath::Fabs( weight_total - 1.0 ) < WWMATH_EPSILON);
  668. pivot->Transform.Translate(trans);
  669. #ifdef ALLOW_TEMPORARIES
  670. pivot->Transform = pivot->Transform * Build_Matrix3D(q0);
  671. #else
  672. pivot->Transform.postMul(Build_Matrix3D(q0,mtx));
  673. #endif
  674. }
  675. #else
  676. if (( weight_total != 0.0f ) && (wcount >= 2)) {
  677. pivot->Transform.Translate( trans / weight_total );
  678. Quaternion q = Slerp_( q0, q1, last_weight / weight_total );
  679. pivot->Transform = pivot->Transform * Build_Matrix3D(q);
  680. } else if (weight_total != 0.0f) {
  681. pivot->Transform.Translate( trans / weight_total );
  682. pivot->Transform = pivot->Transform * Build_Matrix3D(q1);
  683. }
  684. #endif
  685. pivot->IsVisible = false;
  686. for ( anim_num = 0; (anim_num < anim->Get_Num_Anims()) && (!pivot->IsVisible); anim_num++ ) {
  687. HAnimClass *motion = anim->Get_Motion( anim_num );
  688. if ( motion != NULL ) {
  689. float frame_num = anim->Get_Frame( anim_num );
  690. pivot->IsVisible |= motion->Get_Visibility(piv_idx,frame_num);
  691. motion->Release_Ref();
  692. }
  693. }
  694. }
  695. if (pivot->Is_Captured())
  696. {
  697. pivot->Capture_Update();
  698. pivot->IsVisible = true;
  699. }
  700. }
  701. }
  702. /***********************************************************************************************
  703. * HTreeClass::Find_Bone -- Find a bone by name *
  704. * *
  705. * INPUT: *
  706. * *
  707. * OUTPUT: *
  708. * *
  709. * WARNINGS: *
  710. * *
  711. * HISTORY: *
  712. * 11/4/97 GTH : Created. *
  713. *=============================================================================================*/
  714. int HTreeClass::Get_Bone_Index(const char * name) const
  715. {
  716. for (int i=0; i < NumPivots; i++) {
  717. if (stricmp(Pivot[i].Name,name) == 0) {
  718. return i;
  719. }
  720. }
  721. return 0;
  722. }
  723. /***********************************************************************************************
  724. * HTreeClass::Get_Bone_Name -- get the name of a bone from its index *
  725. * *
  726. * INPUT: *
  727. * *
  728. * OUTPUT: *
  729. * *
  730. * WARNINGS: *
  731. * *
  732. * HISTORY: *
  733. * 11/4/97 GTH : Created. *
  734. *=============================================================================================*/
  735. const char * HTreeClass::Get_Bone_Name(int boneidx) const
  736. {
  737. assert(boneidx >= 0);
  738. assert(boneidx < NumPivots);
  739. return Pivot[boneidx].Name;
  740. }
  741. /***********************************************************************************************
  742. * HTreeClass::Get_Parent_Index -- returns index of the parent of the given bone *
  743. * *
  744. * INPUT: *
  745. * boneidx - the bone you are interested in *
  746. * *
  747. * OUTPUT: *
  748. * the index of that bone's parent *
  749. * *
  750. * WARNINGS: *
  751. * *
  752. * HISTORY: *
  753. * 4/12/2000 gth : Created. *
  754. *=============================================================================================*/
  755. int HTreeClass::Get_Parent_Index(int boneidx) const
  756. {
  757. assert(boneidx >= 0);
  758. assert(boneidx < NumPivots);
  759. if (Pivot[boneidx].Parent != NULL) {
  760. return Pivot[boneidx].Parent->Index;
  761. } else {
  762. return 0;
  763. }
  764. }
  765. // Scale this HTree by a constant factor:
  766. void HTreeClass::Scale(float factor)
  767. {
  768. if (factor == 1.0f) return;
  769. // Scale pivot translations
  770. for (int i = 0; i < NumPivots; i++) {
  771. Matrix3D &pivot_transform = Pivot[i].BaseTransform;
  772. Vector3 pivot_translation;
  773. pivot_transform.Get_Translation(&pivot_translation);
  774. pivot_translation *= factor;
  775. pivot_transform.Set_Translation(pivot_translation);
  776. }
  777. // Set state used later to scale animations:
  778. ScaleFactor *= factor;
  779. }
  780. void HTreeClass::Capture_Bone(int boneindex)
  781. {
  782. assert(boneindex >= 0);
  783. assert(boneindex < NumPivots);
  784. #ifdef LAZY_CAP_MTX_ALLOC
  785. if (Pivot[boneindex].CapTransformPtr == NULL)
  786. {
  787. Pivot[boneindex].CapTransformPtr = MSGW3DNEW("PivotClassCaptureBoneMtx") DynamicMatrix3D;
  788. Pivot[boneindex].CapTransformPtr->Mat.Make_Identity();
  789. }
  790. #else
  791. Pivot[boneindex].IsCaptured = true;
  792. #endif
  793. }
  794. void HTreeClass::Release_Bone(int boneindex)
  795. {
  796. assert(boneindex >= 0);
  797. assert(boneindex < NumPivots);
  798. #ifdef LAZY_CAP_MTX_ALLOC
  799. if (Pivot[boneindex].CapTransformPtr)
  800. {
  801. delete Pivot[boneindex].CapTransformPtr;
  802. Pivot[boneindex].CapTransformPtr = NULL;
  803. }
  804. #else
  805. Pivot[boneindex].IsCaptured = false;
  806. #endif
  807. }
  808. bool HTreeClass::Is_Bone_Captured(int boneindex) const
  809. {
  810. assert(boneindex >= 0);
  811. assert(boneindex < NumPivots);
  812. return Pivot[boneindex].Is_Captured();
  813. }
  814. void HTreeClass::Control_Bone(int boneindex,const Matrix3D & relative_tm,bool world_space_translation)
  815. {
  816. assert(boneindex >= 0);
  817. assert(boneindex < NumPivots);
  818. assert(Pivot[boneindex].Is_Captured());
  819. #ifdef LAZY_CAP_MTX_ALLOC
  820. if (Pivot[boneindex].CapTransformPtr == NULL)
  821. return;
  822. Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
  823. Pivot[boneindex].CapTransformPtr->Mat = relative_tm;
  824. #else
  825. Pivot[boneindex].WorldSpaceTranslation = world_space_translation;
  826. Pivot[boneindex].CapTransform = relative_tm;
  827. #endif
  828. }
  829. // Morph the bones on the HTree using weights from a number of other HTrees
  830. HTreeClass * HTreeClass::Create_Morphed( int num_morph_sources,
  831. const float morph_weights[],
  832. const HTreeClass *tree_array[] )
  833. {
  834. int i;
  835. assert(num_morph_sources>0);
  836. for(i=0;i<num_morph_sources;i++) {
  837. assert( tree_array[i] );
  838. assert( morph_weights[i]>=0.0f && morph_weights[i]<=1.0f );
  839. }
  840. for(i=0;i<num_morph_sources-1;i++) {
  841. assert( tree_array[i]->NumPivots == tree_array[i+1]->NumPivots );
  842. }
  843. // Clone the first one,
  844. HTreeClass * new_tree = W3DNEWARRAY HTreeClass( *tree_array[0] );
  845. // Then interpolate all the pivots translations
  846. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  847. Vector3 pos(0.0f,0.0f,0.0f);
  848. for(int nm = 0; nm < num_morph_sources; nm++) {
  849. pos.X += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().X*morph_weights[nm];
  850. pos.Y += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Y*morph_weights[nm];
  851. pos.Z += tree_array[nm]->Pivot[pi].BaseTransform.Get_Translation().Z*morph_weights[nm];
  852. }
  853. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  854. }
  855. return new_tree;
  856. }
  857. // Create an HTree by Interpolating between others
  858. HTreeClass * HTreeClass::Create_Interpolated( const HTreeClass * tree_a0_b0,
  859. const HTreeClass * tree_a0_b1,
  860. const HTreeClass * tree_a1_b0,
  861. const HTreeClass * tree_a1_b1,
  862. float lerp_a, float lerp_b )
  863. {
  864. assert( tree_a0_b0->NumPivots == tree_a0_b1->NumPivots );
  865. assert( tree_a0_b0->NumPivots == tree_a1_b0->NumPivots );
  866. assert( tree_a0_b0->NumPivots == tree_a1_b1->NumPivots );
  867. // Clone the first one,
  868. HTreeClass * new_tree = W3DNEW HTreeClass( *tree_a0_b0 );
  869. // Then interpolate all the pivots translations
  870. Vector3 pos_a0, pos_a1, pos;
  871. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  872. Vector3::Lerp( tree_a0_b0->Pivot[pi].BaseTransform.Get_Translation(),
  873. tree_a0_b1->Pivot[pi].BaseTransform.Get_Translation(),
  874. lerp_b, &pos_a0 );
  875. Vector3::Lerp( tree_a1_b0->Pivot[pi].BaseTransform.Get_Translation(),
  876. tree_a1_b1->Pivot[pi].BaseTransform.Get_Translation(),
  877. lerp_b, &pos_a1 );
  878. Vector3::Lerp( pos_a0, pos_a1, lerp_a, &pos );
  879. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  880. }
  881. return new_tree;
  882. }
  883. // Create an HTree by Interpolating between others
  884. HTreeClass * HTreeClass::Create_Interpolated(const HTreeClass * tree_base,
  885. const HTreeClass * tree_a,
  886. const HTreeClass * tree_b,
  887. float a_scale, float b_scale )
  888. {
  889. WWMEMLOG(MEM_ANIMATION);
  890. assert( tree_base->NumPivots == tree_a->NumPivots );
  891. assert( tree_base->NumPivots == tree_b->NumPivots );
  892. // Clone the first one,
  893. HTreeClass * new_tree = W3DNEW HTreeClass( *tree_base );
  894. float a_scale_abs = WWMath::Fabs( a_scale );
  895. float b_scale_abs = WWMath::Fabs( b_scale );
  896. if ( a_scale_abs + b_scale_abs > 0 ) {
  897. // Then interpolate all the pivots translations
  898. Vector3 pos_a, pos_b, pos;
  899. for (int pi = 0; pi < new_tree->NumPivots; pi++) {
  900. Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
  901. tree_a->Pivot[pi].BaseTransform.Get_Translation(),
  902. a_scale, &pos_a );
  903. Vector3::Lerp( tree_base->Pivot[pi].BaseTransform.Get_Translation(),
  904. tree_b->Pivot[pi].BaseTransform.Get_Translation(),
  905. b_scale, &pos_b );
  906. pos = (pos_a * a_scale_abs + pos_b * b_scale_abs ) / ( a_scale_abs + b_scale_abs );
  907. new_tree->Pivot[pi].BaseTransform.Set_Translation( pos );
  908. }
  909. }
  910. return new_tree;
  911. }