hmorphanim.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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. /***********************************************************************************************
  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:: Byon_g $*
  29. * *
  30. * $Modtime:: 1/16/02 6:39p $*
  31. * *
  32. * $Revision:: 7 $*
  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(AnimName,0,sizeof(AnimName));
  168. memset(HierarchyName,0,sizeof(HierarchyName));
  169. }
  170. HMorphAnimClass::~HMorphAnimClass(void)
  171. {
  172. Free();
  173. }
  174. void HMorphAnimClass::Free(void)
  175. {
  176. if (PoseData != NULL) {
  177. for (int i=0; i<ChannelCount; i++) {
  178. REF_PTR_RELEASE(PoseData[i]);
  179. }
  180. delete[] PoseData;
  181. PoseData = NULL;
  182. }
  183. if (MorphKeyData != NULL) {
  184. delete[] MorphKeyData;
  185. MorphKeyData = NULL;
  186. }
  187. if (PivotChannel != NULL) {
  188. delete[] PivotChannel;
  189. PivotChannel = NULL;
  190. }
  191. }
  192. static int Build_List_From_String
  193. (
  194. const char * buffer,
  195. const char * delimiter,
  196. StringClass ** string_list
  197. )
  198. {
  199. int count = 0;
  200. WWASSERT (buffer != NULL);
  201. WWASSERT (delimiter != NULL);
  202. WWASSERT (string_list != NULL);
  203. if ((buffer != NULL) &&
  204. (delimiter != NULL) &&
  205. (string_list != NULL))
  206. {
  207. int delim_len = ::strlen (delimiter);
  208. //
  209. // Determine how many entries there will be in the list
  210. //
  211. for (const char *entry = buffer;
  212. (entry != NULL) && (entry[1] != 0);
  213. entry = ::strstr (entry, delimiter))
  214. {
  215. //
  216. // Move past the current delimiter (if necessary)
  217. //
  218. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  219. entry += delim_len;
  220. }
  221. // Increment the count of entries
  222. count ++;
  223. }
  224. if (count > 0) {
  225. //
  226. // Allocate enough StringClass objects to hold all the strings in the list
  227. //
  228. (*string_list) = W3DNEWARRAY StringClass[count];
  229. //
  230. // Parse the string and pull out its entries.
  231. //
  232. count = 0;
  233. for (entry = buffer;
  234. (entry != NULL) && (entry[1] != 0);
  235. entry = ::strstr (entry, delimiter))
  236. {
  237. //
  238. // Move past the current delimiter (if necessary)
  239. //
  240. if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
  241. entry += delim_len;
  242. }
  243. //
  244. // Copy this entry into its own string
  245. //
  246. StringClass entry_string = entry;
  247. char *delim_start = ::strstr (entry_string, delimiter);
  248. if (delim_start != NULL) {
  249. delim_start[0] = 0;
  250. }
  251. //
  252. // Add this entry to our list
  253. //
  254. if ((entry_string.Get_Length () > 0) || (count == 0)) {
  255. (*string_list)[count++] = entry_string;
  256. }
  257. }
  258. } else if (delim_len > 0) {
  259. count = 1;
  260. (*string_list) = W3DNEWARRAY StringClass[count];
  261. (*string_list)[0] = buffer;
  262. }
  263. }
  264. //
  265. // Return the number of entries in our list
  266. //
  267. return count;
  268. }
  269. bool Is_Number (const char *str)
  270. {
  271. bool retval = true;
  272. while (retval && str[0] != NULL){
  273. retval = ((str[0] >= '0' && str[0] <= '9') || str[0] == '-' || str[0] == '.');
  274. str ++;
  275. }
  276. return retval;
  277. }
  278. bool HMorphAnimClass::Import(const char *hierarchy_name, TextFileClass &text_desc)
  279. {
  280. bool retval = false;
  281. Free ();
  282. FrameCount = 0;
  283. FrameRate = 30.0F;
  284. //
  285. // Copy the hierarchy name into a class variable
  286. //
  287. ::strncpy (HierarchyName, hierarchy_name, W3D_NAME_LEN);
  288. HierarchyName[W3D_NAME_LEN - 1] = 0;
  289. //
  290. // Attempt to load the new base pose
  291. //
  292. HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
  293. WWASSERT (base_pose != NULL);
  294. NumNodes = base_pose->Num_Pivots();
  295. //
  296. // Read the header from the file
  297. //
  298. StringClass header;
  299. bool success = text_desc.Read_Line (header);
  300. if (success) {
  301. //
  302. // Get the list of comma-delimited strings from the header
  303. //
  304. StringClass *column_list = NULL;
  305. int column_count = Build_List_From_String (header, ",", &column_list);
  306. //
  307. // The first column header should be 'Frame#', all other headers
  308. // should be channel animation names.
  309. //
  310. ChannelCount = column_count - 1;
  311. WWASSERT (ChannelCount > 0);
  312. if (ChannelCount > 0) {
  313. //
  314. // Allocate and initialize each animation channel
  315. //
  316. PoseData = W3DNEWARRAY HAnimClass *[ChannelCount];
  317. MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
  318. for (int index = 0; index < ChannelCount; index ++) {
  319. StringClass channel_anim_name;
  320. channel_anim_name.Format ("%s.%s", HierarchyName, (const char *)column_list[index + 1]);
  321. PoseData[index] = WW3DAssetManager::Get_Instance()->Get_HAnim (channel_anim_name);
  322. }
  323. //
  324. // Now read the animation data for each frame
  325. //
  326. StringClass frame_desc;
  327. while (text_desc.Read_Line (frame_desc)) {
  328. //
  329. // Get the frame descriptions from this line
  330. //
  331. StringClass *channel_list = NULL;
  332. int list_count = Build_List_From_String (frame_desc, ",", &channel_list);
  333. WWASSERT (list_count > 0);
  334. if (list_count > 0) {
  335. //
  336. // The first column contains the morph frame number
  337. //
  338. int frame = ::atoi (channel_list[0]);
  339. //
  340. // Now read the animation frame number for each channel
  341. //
  342. for (int index = 1; index < list_count; index ++) {
  343. StringClass &channel_frame = channel_list[index];
  344. //
  345. // If this channel contains a valid number, then record
  346. // its animation frame
  347. //
  348. if (::Is_Number (channel_frame)) {
  349. MorphKeyData[index - 1].Add_Key (frame, ::atoi (channel_frame));
  350. }
  351. }
  352. FrameCount = frame + 1;
  353. }
  354. //
  355. // Cleanup
  356. //
  357. if (channel_list != NULL) {
  358. delete [] channel_list;
  359. channel_list = NULL;
  360. }
  361. }
  362. //
  363. // Allocate the pivot channel list
  364. //
  365. PivotChannel = W3DNEWARRAY uint32[NumNodes];
  366. Resolve_Pivot_Channels ();
  367. }
  368. //
  369. // Cleanup
  370. //
  371. if (column_list != NULL) {
  372. delete [] column_list;
  373. column_list = NULL;
  374. }
  375. }
  376. return retval;
  377. }
  378. void HMorphAnimClass::Resolve_Pivot_Channels(void)
  379. {
  380. WWASSERT (PivotChannel != NULL);
  381. //
  382. // Loop over all the pivots in the HTree
  383. //
  384. for (int pivot = 0; pivot < NumNodes; pivot ++) {
  385. PivotChannel[pivot] = 0;
  386. //
  387. // Find out which animation channel affects this pivot
  388. //
  389. for (int channel = 0; channel < ChannelCount; channel ++) {
  390. if (PoseData[channel]->Is_Node_Motion_Present (pivot)) {
  391. PivotChannel[pivot] = channel;
  392. }
  393. }
  394. }
  395. return ;
  396. }
  397. void HMorphAnimClass::Set_Name(const char * name)
  398. {
  399. //
  400. // Copy the full name
  401. //
  402. ::strcpy (Name, name);
  403. //
  404. // Try to find the separator (a period)
  405. //
  406. StringClass full_name = name;
  407. char *separator = ::strchr (full_name, '.');
  408. if (separator != NULL) {
  409. //
  410. // Null out the separator and copy the two names
  411. // into our two buffers
  412. //
  413. separator[0] = 0;
  414. ::strcpy (AnimName, separator + 1);
  415. ::strcpy (HierarchyName, full_name);
  416. }
  417. return ;
  418. }
  419. void HMorphAnimClass::Free_Morph(void)
  420. {
  421. Free();
  422. }
  423. int HMorphAnimClass::Create_New_Morph(const int channels, HAnimClass *anim[])
  424. {
  425. // clean out the previous instance of this class
  426. Free();
  427. // set the number of channels
  428. ChannelCount = channels;
  429. // read in the animation header
  430. if (anim == NULL) {
  431. return LOAD_ERROR;
  432. }
  433. // set up info
  434. // FrameCount = anim[0]->Get_Num_Frames();
  435. FrameCount = 0;
  436. FrameRate = anim[0]->Get_Frame_Rate();
  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. }