hmorphanim.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/hmorphanim.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Jani_p $*
  29. * *
  30. * $Modtime:: 6/27/01 7:50p $*
  31. * *
  32. * $Revision:: 5 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "hmorphanim.h"
  38. #include "w3d_file.h"
  39. #include "chunkio.h"
  40. #include "assetmgr.h"
  41. #include "htree.h"
  42. #include "wwstring.h"
  43. #include "textfile.h"
  44. #include "simplevec.h"
  45. TimeCodedMorphKeysClass::TimeCodedMorphKeysClass(void)
  46. : CachedIdx (0)
  47. {
  48. }
  49. TimeCodedMorphKeysClass::~TimeCodedMorphKeysClass(void)
  50. {
  51. Free();
  52. }
  53. void TimeCodedMorphKeysClass::Free(void)
  54. {
  55. Keys.Delete_All ();
  56. CachedIdx = 0;
  57. }
  58. bool TimeCodedMorphKeysClass::Load_W3D(ChunkLoadClass & cload)
  59. {
  60. Free();
  61. uint32 key_count = cload.Cur_Chunk_Length() / sizeof(W3dMorphAnimKeyStruct);
  62. W3dMorphAnimKeyStruct w3dkey;
  63. for (uint32 i=0; i<key_count; i++) {
  64. cload.Read(&w3dkey,sizeof(w3dkey));
  65. Keys.Add (MorphKeyStruct (w3dkey.MorphFrame, w3dkey.PoseFrame));
  66. }
  67. CachedIdx = 0;
  68. return true;
  69. }
  70. bool TimeCodedMorphKeysClass::Save_W3D(ChunkSaveClass & csave)
  71. {
  72. W3dMorphAnimKeyStruct w3dkey;
  73. for (int i=0; i<Keys.Count (); i++) {
  74. w3dkey.MorphFrame = Keys[i].MorphFrame;
  75. w3dkey.PoseFrame = Keys[i].PoseFrame;
  76. csave.Write(&w3dkey,sizeof(w3dkey));
  77. }
  78. return true;
  79. }
  80. void TimeCodedMorphKeysClass::Add_Key (uint32 morph_frame, uint32 pose_frame)
  81. {
  82. Keys.Add (MorphKeyStruct (morph_frame, pose_frame));
  83. return ;
  84. }
  85. void TimeCodedMorphKeysClass::Get_Morph_Info(float morph_frame,int * pose_frame0,int * pose_frame1,float * fraction)
  86. {
  87. if (morph_frame < 0.0f) {
  88. *pose_frame0 = *pose_frame1 = Keys[0].PoseFrame;
  89. *fraction = 0.0f;
  90. return;
  91. }
  92. if (morph_frame >= Keys[Keys.Count ()-1].MorphFrame) {
  93. *pose_frame0 = *pose_frame1 = Keys[Keys.Count ()-1].PoseFrame;
  94. *fraction = 0.0f;
  95. return;
  96. }
  97. int key_index = get_index(morph_frame);
  98. *pose_frame0 = Keys[key_index].PoseFrame;
  99. *pose_frame1 = Keys[key_index+1].PoseFrame;
  100. *fraction = (morph_frame - Keys[key_index].MorphFrame) / (Keys[key_index+1].MorphFrame - Keys[key_index].MorphFrame);
  101. }
  102. uint32 TimeCodedMorphKeysClass::get_index(float frame)
  103. {
  104. assert(CachedIdx <= (uint32)Keys.Count ()-1);
  105. float cached_frame = Keys[CachedIdx].MorphFrame;
  106. // check if the requested time is in the cached interval or the following one
  107. if (frame >= cached_frame) {
  108. // special case for end packets
  109. if (CachedIdx == (uint32)Keys.Count ()-1) return(CachedIdx);
  110. // check if the requested time is still in the cached interval
  111. if (frame < Keys[CachedIdx + 1].MorphFrame) return(CachedIdx);
  112. // do one time look-ahead before reverting to a search
  113. CachedIdx++;
  114. // again, special case the end interval
  115. if (CachedIdx == (uint32)Keys.Count ()-1) return(CachedIdx);
  116. // check if requested time is in this interval
  117. if (frame < Keys[CachedIdx + 1].MorphFrame) return(CachedIdx);
  118. }
  119. // nope, fall back to a binary search for the requested interval
  120. CachedIdx = binary_search_index(frame);
  121. return(CachedIdx);
  122. }
  123. uint32 TimeCodedMorphKeysClass::binary_search_index(float req_frame)
  124. {
  125. // special case first and last packet
  126. if (req_frame < Keys[0].MorphFrame) return 0;
  127. if (req_frame >= Keys[Keys.Count ()-1].MorphFrame) return Keys.Count ()-1;
  128. int leftIdx = 0;
  129. int rightIdx = Keys.Count ();
  130. int idx,dx;
  131. // binary search for the desired interval
  132. for (;;) {
  133. // if we've zeroed in on the interval, return the left index
  134. dx = rightIdx - leftIdx;
  135. if (dx == 1) {
  136. WWASSERT(req_frame >= Keys[leftIdx].MorphFrame);
  137. WWASSERT(req_frame < Keys[rightIdx].MorphFrame);
  138. return leftIdx;
  139. }
  140. // otherwise, split our interval in half and descend into one of them
  141. dx>>=1;
  142. idx = leftIdx + dx;
  143. if (req_frame < Keys[idx].MorphFrame) {
  144. rightIdx = idx;
  145. } else {
  146. leftIdx = idx;
  147. }
  148. }
  149. assert(0);
  150. return(0);
  151. }
  152. /*********************************************************************************************
  153. **
  154. ** HMorphAnimClass Implementation
  155. **
  156. *********************************************************************************************/
  157. HMorphAnimClass::HMorphAnimClass(void) :
  158. FrameCount(0),
  159. FrameRate(0.0f),
  160. ChannelCount(0),
  161. NumNodes(0),
  162. PoseData(NULL),
  163. MorphKeyData(NULL),
  164. PivotChannel(NULL)
  165. {
  166. memset(Name,0,sizeof(Name));
  167. memset(HierarchyName,0,sizeof(HierarchyName));
  168. }
  169. HMorphAnimClass::~HMorphAnimClass(void)
  170. {
  171. Free();
  172. }
  173. void HMorphAnimClass::Free(void)
  174. {
  175. if (PoseData != NULL) {
  176. for (int i=0; i<ChannelCount; i++) {
  177. REF_PTR_RELEASE(PoseData[i]);
  178. }
  179. delete[] PoseData;
  180. PoseData = NULL;
  181. }
  182. if (MorphKeyData != NULL) {
  183. delete[] MorphKeyData;
  184. MorphKeyData = NULL;
  185. }
  186. if (PivotChannel != NULL) {
  187. delete[] PivotChannel;
  188. PivotChannel = NULL;
  189. }
  190. }
  191. int Build_List_From_String
  192. (
  193. const char * buffer,
  194. const char * delimiter,
  195. StringClass ** string_list
  196. )
  197. {
  198. int count = 0;
  199. WWASSERT (buffer != NULL);
  200. WWASSERT (delimiter != NULL);
  201. WWASSERT (string_list != NULL);
  202. if ((buffer != NULL) &&
  203. (delimiter != NULL) &&
  204. (string_list != NULL))
  205. {
  206. int delim_len = ::strlen (delimiter);
  207. //
  208. // Determine how many entries there will be in the list
  209. //
  210. for (const char *entry = buffer;
  211. (entry != NULL) && (entry[1] != 0);
  212. entry = ::strstr (entry, delimiter))
  213. {
  214. //
  215. // Move past the current delimiter (if necessary)
  216. //
  217. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  218. entry += delim_len;
  219. }
  220. // Increment the count of entries
  221. count ++;
  222. }
  223. if (count > 0) {
  224. //
  225. // Allocate enough StringClass objects to hold all the strings in the list
  226. //
  227. (*string_list) = W3DNEWARRAY StringClass[count];
  228. //
  229. // Parse the string and pull out its entries.
  230. //
  231. count = 0;
  232. for (entry = buffer;
  233. (entry != NULL) && (entry[1] != 0);
  234. entry = ::strstr (entry, delimiter))
  235. {
  236. //
  237. // Move past the current delimiter (if necessary)
  238. //
  239. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  240. entry += delim_len;
  241. }
  242. //
  243. // Copy this entry into its own string
  244. //
  245. StringClass entry_string = entry;
  246. char *delim_start = ::strstr (entry_string, delimiter);
  247. if (delim_start != NULL) {
  248. delim_start[0] = 0;
  249. }
  250. //
  251. // Add this entry to our list
  252. //
  253. if ((entry_string.Get_Length () > 0) || (count == 0)) {
  254. (*string_list)[count++] = entry_string;
  255. }
  256. }
  257. } else if (delim_len > 0) {
  258. count = 1;
  259. (*string_list) = W3DNEWARRAY StringClass[count];
  260. (*string_list)[0] = buffer;
  261. }
  262. }
  263. //
  264. // Return the number of entries in our list
  265. //
  266. return count;
  267. }
  268. bool Is_Number (const char *str)
  269. {
  270. bool retval = true;
  271. while (retval && str[0] != NULL){
  272. retval = ((str[0] >= '0' && str[0] <= '9') || str[0] == '-' || str[0] == '.');
  273. str ++;
  274. }
  275. return retval;
  276. }
  277. bool HMorphAnimClass::Import(const char *hierarchy_name, TextFileClass &text_desc)
  278. {
  279. bool retval = false;
  280. Free ();
  281. FrameCount = 0;
  282. FrameRate = 30.0F;
  283. //
  284. // Copy the hierarchy name into a class variable
  285. //
  286. ::strncpy (HierarchyName, hierarchy_name, W3D_NAME_LEN);
  287. HierarchyName[W3D_NAME_LEN - 1] = 0;
  288. //
  289. // Attempt to load the new base pose
  290. //
  291. HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
  292. WWASSERT (base_pose != NULL);
  293. NumNodes = base_pose->Num_Pivots();
  294. //
  295. // Read the header from the file
  296. //
  297. StringClass header;
  298. bool success = text_desc.Read_Line (header);
  299. if (success) {
  300. //
  301. // Get the list of comma-delimited strings from the header
  302. //
  303. StringClass *column_list = NULL;
  304. int column_count = Build_List_From_String (header, ",", &column_list);
  305. //
  306. // The first column header should be 'Frame#', all other headers
  307. // should be channel animation names.
  308. //
  309. ChannelCount = column_count - 1;
  310. WWASSERT (ChannelCount > 0);
  311. if (ChannelCount > 0) {
  312. //
  313. // Allocate and initialize each animation channel
  314. //
  315. PoseData = W3DNEWARRAY HAnimClass *[ChannelCount];
  316. MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
  317. for (int index = 0; index < ChannelCount; index ++) {
  318. StringClass channel_anim_name;
  319. channel_anim_name.Format ("%s.%s", HierarchyName, (const char *)column_list[index + 1]);
  320. PoseData[index] = WW3DAssetManager::Get_Instance()->Get_HAnim (channel_anim_name);
  321. }
  322. //
  323. // Now read the animation data for each frame
  324. //
  325. StringClass frame_desc;
  326. while (text_desc.Read_Line (frame_desc)) {
  327. //
  328. // Get the frame descriptions from this line
  329. //
  330. StringClass *channel_list = NULL;
  331. int list_count = Build_List_From_String (frame_desc, ",", &channel_list);
  332. WWASSERT (list_count > 0);
  333. if (list_count > 0) {
  334. //
  335. // The first column contains the morph frame number
  336. //
  337. int frame = ::atoi (channel_list[0]);
  338. //
  339. // Now read the animation frame number for each channel
  340. //
  341. for (int index = 1; index < list_count; index ++) {
  342. StringClass &channel_frame = channel_list[index];
  343. //
  344. // If this channel contains a valid number, then record
  345. // its animation frame
  346. //
  347. if (::Is_Number (channel_frame)) {
  348. MorphKeyData[index - 1].Add_Key (frame, ::atoi (channel_frame));
  349. }
  350. }
  351. FrameCount = frame + 1;
  352. }
  353. //
  354. // Cleanup
  355. //
  356. if (channel_list != NULL) {
  357. delete [] channel_list;
  358. channel_list = NULL;
  359. }
  360. }
  361. //
  362. // Allocate the pivot channel list
  363. //
  364. PivotChannel = W3DNEWARRAY uint32[NumNodes];
  365. Resolve_Pivot_Channels ();
  366. }
  367. //
  368. // Cleanup
  369. //
  370. if (column_list != NULL) {
  371. delete [] column_list;
  372. column_list = NULL;
  373. }
  374. }
  375. return retval;
  376. }
  377. void HMorphAnimClass::Resolve_Pivot_Channels(void)
  378. {
  379. WWASSERT (PivotChannel != NULL);
  380. //
  381. // Loop over all the pivots in the HTree
  382. //
  383. for (int pivot = 0; pivot < NumNodes; pivot ++) {
  384. PivotChannel[pivot] = 0;
  385. //
  386. // Find out which animation channel affects this pivot
  387. //
  388. for (int channel = 0; channel < ChannelCount; channel ++) {
  389. if (PoseData[channel]->Is_Node_Motion_Present (pivot)) {
  390. PivotChannel[pivot] = channel;
  391. }
  392. }
  393. }
  394. return ;
  395. }
  396. void HMorphAnimClass::Set_Name(const char * name)
  397. {
  398. //
  399. // Copy the full name
  400. //
  401. ::strcpy (Name, name);
  402. //
  403. // Try to find the separator (a period)
  404. //
  405. StringClass full_name = name;
  406. char *separator = ::strchr (full_name, '.');
  407. if (separator != NULL) {
  408. //
  409. // Null out the separator and copy the two names
  410. // into our two buffers
  411. //
  412. separator[0] = 0;
  413. ::strcpy (AnimName, separator + 1);
  414. ::strcpy (HierarchyName, full_name);
  415. }
  416. return ;
  417. }
  418. void HMorphAnimClass::Free_Morph(void)
  419. {
  420. Free();
  421. }
  422. int HMorphAnimClass::Create_New_Morph(const int channels, HAnimClass *anim[])
  423. {
  424. // clean out the previous instance of this class
  425. Free();
  426. // set the number of channels
  427. ChannelCount = channels;
  428. // read in the animation header
  429. if (anim == NULL) {
  430. return LOAD_ERROR;
  431. }
  432. // set up info
  433. // FrameCount = anim[0]->Get_Num_Frames();
  434. // FrameRate = anim[0]->Get_Frame_Rate();
  435. FrameCount = 0;
  436. FrameRate = 30.0f;
  437. NumNodes = anim[0]->Get_Num_Pivots();
  438. // Set up the anim data for all the channels
  439. PoseData = W3DNEWARRAY HAnimClass * [ChannelCount];
  440. for(int i=0;i<ChannelCount;i++)
  441. PoseData[i] = anim[i];
  442. // Create a timecodekey array for each channel and initialize the pivot channels
  443. MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
  444. PivotChannel = W3DNEWARRAY uint32[NumNodes];
  445. // Resolve the pivots so that they correspond to the proper morphing channels
  446. memset(PivotChannel,0,NumNodes * sizeof(uint32));
  447. Resolve_Pivot_Channels();
  448. // Signal successful process
  449. return OK;
  450. }
  451. int HMorphAnimClass::Load_W3D(ChunkLoadClass & cload)
  452. {
  453. Free();
  454. // read in the animation header
  455. W3dMorphAnimHeaderStruct header;
  456. cload.Open_Chunk();
  457. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_HEADER);
  458. cload.Read(&header,sizeof(header));
  459. cload.Close_Chunk();
  460. strncpy(AnimName,header.Name,sizeof(AnimName));
  461. strncpy(HierarchyName,header.HierarchyName,sizeof(HierarchyName));
  462. strcpy(Name,HierarchyName);
  463. strcat(Name,".");
  464. strcat(Name,AnimName);
  465. HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
  466. if (base_pose == NULL) {
  467. return LOAD_ERROR;
  468. }
  469. NumNodes = base_pose->Num_Pivots();
  470. FrameCount = header.FrameCount;
  471. FrameRate = header.FrameRate;
  472. ChannelCount = header.ChannelCount;
  473. PoseData = W3DNEWARRAY HAnimClass * [ChannelCount];
  474. MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
  475. PivotChannel = W3DNEWARRAY uint32[NumNodes];
  476. memset(PivotChannel,0,NumNodes * sizeof(uint32));
  477. // read in the rest of the chunks
  478. int cur_channel = 0;
  479. while (cload.Open_Chunk()) {
  480. switch(cload.Cur_Chunk_ID())
  481. {
  482. case W3D_CHUNK_MORPHANIM_CHANNEL:
  483. read_channel(cload,cur_channel++);
  484. break;
  485. case W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA:
  486. cload.Read(PivotChannel,cload.Cur_Chunk_Length());
  487. break;
  488. };
  489. cload.Close_Chunk();
  490. }
  491. return OK;
  492. }
  493. void HMorphAnimClass::read_channel(ChunkLoadClass & cload,int channel)
  494. {
  495. WWASSERT(channel >= 0);
  496. WWASSERT(channel < ChannelCount);
  497. StringClass anim_name;
  498. cload.Open_Chunk();
  499. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_POSENAME);
  500. cload.Read(anim_name.Get_Buffer(cload.Cur_Chunk_Length()),cload.Cur_Chunk_Length());
  501. cload.Close_Chunk();
  502. //StringClass channel_anim_name;
  503. //channel_anim_name.Format ("%s.%s", HierarchyName, anim_name);
  504. PoseData[channel] = WW3DAssetManager::Get_Instance()->Get_HAnim(anim_name);
  505. WWASSERT(PoseData[channel] != NULL);
  506. cload.Open_Chunk();
  507. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_KEYDATA);
  508. MorphKeyData[channel].Load_W3D(cload);
  509. cload.Close_Chunk();
  510. }
  511. int HMorphAnimClass::Save_W3D(ChunkSaveClass & csave)
  512. {
  513. // W3D objects write their own wrapper chunks
  514. csave.Begin_Chunk(W3D_CHUNK_MORPH_ANIMATION);
  515. // init the header data
  516. W3dMorphAnimHeaderStruct header;
  517. memset(&header,0,sizeof(header));
  518. strncpy(header.Name,AnimName,sizeof(header.Name));
  519. strncpy(header.HierarchyName,HierarchyName,sizeof(header.HierarchyName));
  520. header.FrameCount = FrameCount;
  521. header.FrameRate = FrameRate;
  522. header.ChannelCount = ChannelCount;
  523. // write out the animation header
  524. csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_HEADER);
  525. csave.Write(&header,sizeof(header));
  526. csave.End_Chunk();
  527. // write out the morph channels
  528. for (int ci=0; ci<ChannelCount; ci++) {
  529. csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_CHANNEL);
  530. write_channel(csave,ci);
  531. csave.End_Chunk();
  532. }
  533. // write out the pivot attachments
  534. csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA);
  535. csave.Write(PivotChannel,NumNodes * sizeof(uint32));
  536. csave.End_Chunk();
  537. csave.End_Chunk();
  538. return OK;
  539. }
  540. void HMorphAnimClass::write_channel(ChunkSaveClass & csave,int channel)
  541. {
  542. WWASSERT(PoseData[channel] != NULL);
  543. const char * pose_name = PoseData[channel]->Get_Name();
  544. csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_POSENAME);
  545. csave.Write(pose_name,strlen(pose_name) + 1);
  546. csave.End_Chunk();
  547. csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_KEYDATA);
  548. MorphKeyData[channel].Save_W3D(csave);
  549. csave.End_Chunk();
  550. }
  551. void HMorphAnimClass::Get_Translation(Vector3& trans,int pividx,float frame) const
  552. {
  553. int channel = PivotChannel[pividx];
  554. int pose_frame0,pose_frame1;
  555. float fraction;
  556. MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
  557. Vector3 t0;
  558. PoseData[channel]->Get_Translation(t0,pividx,pose_frame0);
  559. Vector3 t1;
  560. PoseData[channel]->Get_Translation(t1,pividx,pose_frame1);
  561. Vector3::Lerp(t0,t1,fraction,&trans);
  562. }
  563. void HMorphAnimClass::Get_Orientation(Quaternion& q, int pividx,float frame) const
  564. {
  565. int channel = PivotChannel[pividx];
  566. int pose_frame0,pose_frame1;
  567. float fraction;
  568. MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
  569. Quaternion q0;
  570. PoseData[channel]->Get_Orientation(q0,pividx,pose_frame0);
  571. Quaternion q1;
  572. PoseData[channel]->Get_Orientation(q1,pividx,pose_frame1);
  573. ::Fast_Slerp(q,q0,q1,fraction);
  574. }
  575. void HMorphAnimClass::Get_Transform(Matrix3D& mtx,int pividx,float frame) const
  576. {
  577. int channel = PivotChannel[pividx];
  578. int pose_frame0,pose_frame1;
  579. float fraction;
  580. MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
  581. Quaternion q0;
  582. PoseData[channel]->Get_Orientation(q0,pividx,pose_frame0);
  583. Quaternion q1;
  584. PoseData[channel]->Get_Orientation(q1,pividx,pose_frame1);
  585. Quaternion q;
  586. ::Fast_Slerp(q,q0,q1,fraction);
  587. ::Build_Matrix3D(q,mtx);
  588. Vector3 t0;
  589. PoseData[channel]->Get_Translation(t0,pividx,pose_frame0);
  590. Vector3 t1;
  591. PoseData[channel]->Get_Translation(t1,pividx,pose_frame1);
  592. Vector3 trans;
  593. Vector3::Lerp(t0,t1,fraction,&trans);
  594. mtx.Set_Translation(trans);
  595. }
  596. void HMorphAnimClass::Insert_Morph_Key(const int channel, uint32 morph_frame, uint32 pose_frame)
  597. {
  598. assert(channel<ChannelCount);
  599. MorphKeyData[channel].Add_Key(morph_frame,pose_frame);
  600. // update the framecount to reflect the newly added key
  601. FrameCount = WWMath::Max(morph_frame,FrameCount);
  602. }
  603. void HMorphAnimClass::Release_Keys(void)
  604. {
  605. for(int i=0;i<ChannelCount;i++)
  606. MorphKeyData[i].Free();
  607. // update the framecount as 0
  608. FrameCount = 0;
  609. }