AnimSet.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdH.h"
  13. #include <Engine/Ska/AnimSet.h>
  14. #include <Engine/Templates/StaticArray.h>
  15. #include <Engine/Base/CTString.h>
  16. #include <Engine/Ska/StringTable.h>
  17. #include <Engine/Templates/StaticArray.cpp>
  18. #include <Engine/templates/DynamicContainer.cpp>
  19. #include <Engine/Base/Stream.h>
  20. #include <Engine/Base/Console.h>
  21. #include <Engine/Math/Functions.h>
  22. #include <Engine/Math/Geometry.h>
  23. #include <Engine/Base/Timer.h>
  24. #define ANIMSET_VERSION 14
  25. #define ANIMSET_ID "ANIM"
  26. // table for removed frames
  27. static CStaticArray<BOOL> aiRemFrameTable;
  28. // precalculated angles for rotations
  29. static CStaticArray<ANGLE3D> aangAngles;
  30. // if rotations are compresed does loader also fills array of uncompresed rotations
  31. static BOOL bAllRotations = FALSE;
  32. void RememberUnCompresedRotatations(BOOL bRemember)
  33. {
  34. bAllRotations = bRemember;
  35. }
  36. CAnimSet::CAnimSet()
  37. {
  38. }
  39. CAnimSet::~CAnimSet()
  40. {
  41. }
  42. // conpres normal
  43. static void CompressAxis(const FLOAT3D &vNormal, UWORD &ubH, UWORD &ubP)
  44. {
  45. ANGLE h, p;
  46. const FLOAT &x = vNormal(1);
  47. const FLOAT &y = vNormal(2);
  48. const FLOAT &z = vNormal(3);
  49. // calculate pitch
  50. p = ASin(y);
  51. // if y is near +1 or -1
  52. if (y>0.99999 || y<-0.99999) {
  53. // heading is irrelevant
  54. h = 0;
  55. // otherwise
  56. } else {
  57. // calculate heading
  58. h = ATan2(-x, -z);
  59. }
  60. h = (h/360.0f)+0.5f;
  61. p = (p/360.0f)+0.5f;
  62. ASSERT(h>=0 && h<=1);
  63. ASSERT(p>=0 && p<=1);
  64. ubH = UWORD(h*65535);
  65. ubP = UWORD(p*65535);
  66. }
  67. // try to remove 2. keyframe in rotation
  68. BOOL RemoveRotFrame(AnimRot &ar1,AnimRot &ar2,AnimRot &ar3,FLOAT fTreshold)
  69. {
  70. ANGLE3D ang1,ang2,ang2i,ang3;
  71. FLOATmatrix3D m2i;
  72. // calculate slerp factor for ar2'
  73. FLOAT fSlerpFactor = (FLOAT)(ar2.ar_iFrameNum - ar1.ar_iFrameNum)/(FLOAT)(ar3.ar_iFrameNum - ar1.ar_iFrameNum);
  74. // calculate ar2'
  75. FLOATquat3D q2i = Slerp<FLOAT>(fSlerpFactor,ar1.ar_qRot,ar3.ar_qRot);
  76. // read precalculated values
  77. ang1 = aangAngles[ar1.ar_iFrameNum];
  78. ang2 = aangAngles[ar2.ar_iFrameNum];
  79. ang3 = aangAngles[ar3.ar_iFrameNum];
  80. q2i.ToMatrix(m2i);
  81. DecomposeRotationMatrixNoSnap(ang2i,m2i);
  82. for(INDEX i=1;i<4;i++)
  83. {
  84. if( ((ang2(i) < ang3(i)) && (ang2(i) < ang1(i))) || ((ang2(i) > ang3(i)) && (ang2(i) > ang1(i))) )
  85. {
  86. // this is extrem
  87. if(Abs(ang2(i)) > 0.1f) return FALSE;
  88. }
  89. FLOAT fErr = Abs(ang2(i)-ang2i(i)) / Abs(ang3(i) - ang1(i));
  90. if(Abs(ang2(i)-ang2i(i)) < 0.1f) continue;
  91. if(fErr>fTreshold) return FALSE;
  92. }
  93. return TRUE;
  94. }
  95. // try to remove 2. keyrame in translation
  96. BOOL RemovePosFrame(AnimPos &ap1,AnimPos &ap2,AnimPos &ap3,FLOAT fTreshold)
  97. {
  98. FLOAT fLerpFactor = (FLOAT)(ap2.ap_iFrameNum - ap1.ap_iFrameNum)/(FLOAT)(ap3.ap_iFrameNum - ap1.ap_iFrameNum);
  99. FLOAT3D v2i = Lerp(ap1.ap_vPos,ap3.ap_vPos,fLerpFactor);
  100. FLOAT3D v1 = ap1.ap_vPos;
  101. FLOAT3D v2 = ap2.ap_vPos;
  102. FLOAT3D v3 = ap3.ap_vPos;
  103. for(INDEX i=1;i<4;i++)
  104. {
  105. if( ((v2(i) < v3(i)) && (v2(i) < v1(i))) || ((v2(i) > v3(i)) && (v2(i) > v1(i))) )
  106. {
  107. // extrem
  108. if(Abs(v2(i)) > 0.001f) return FALSE;
  109. }
  110. FLOAT fErr = Abs(v2(i)-v2i(i)) / Abs(v3(i) - v1(i));
  111. if(Abs(v2(i)-v2i(i)) < 0.001f) continue;
  112. if(fErr>fTreshold) return FALSE;
  113. }
  114. return TRUE;
  115. }
  116. // find next keyframe that havent been marked as removed
  117. INDEX FindNextFrame(INDEX ifnToFind)
  118. {
  119. INDEX ctfn = aiRemFrameTable.Count();
  120. if(ifnToFind >= ctfn) return -1;
  121. if(aiRemFrameTable[ifnToFind] == FALSE) return ifnToFind;
  122. for(INDEX ifn=ifnToFind;ifn<ctfn;ifn++)
  123. {
  124. if(aiRemFrameTable[ifn] == FALSE) return ifn;
  125. }
  126. return -1;
  127. }
  128. // optimize all animations
  129. void CAnimSet::Optimize()
  130. {
  131. INDEX ctan=as_Anims.Count();
  132. for(INDEX ian=0;ian<ctan;ian++)
  133. {
  134. Animation &an = as_Anims[ian];
  135. //CalculateExtraSpins(an);
  136. OptimizeAnimation(an,an.an_fTreshold);
  137. }
  138. }
  139. // optimize animation
  140. void CAnimSet::OptimizeAnimation(Animation &an, FLOAT fTreshold)
  141. {
  142. INDEX ctfn = an.an_iFrames;
  143. INDEX ctbe = an.an_abeBones.Count();
  144. aiRemFrameTable.Clear();
  145. aiRemFrameTable.New(ctfn);
  146. aangAngles.Clear();
  147. aangAngles.New(ctfn);
  148. for(INDEX ibe=0;ibe<ctbe;ibe++)
  149. {
  150. BoneEnvelope &be = an.an_abeBones[ibe];
  151. // calculate length on bone in default pos
  152. be.be_OffSetLen = (FLOAT3D(be.be_mDefaultPos[3],be.be_mDefaultPos[7],be.be_mDefaultPos[11])).Length();
  153. // create a table for removed frames
  154. memset(&aiRemFrameTable[0],0,sizeof(BOOL)*ctfn);
  155. memset(&aangAngles[0],0,sizeof(ANGLE3D)*ctfn);
  156. // fill array of decomposed matrices
  157. FLOATmatrix3D mat;
  158. for(INDEX im=0;im<ctfn;im++)
  159. {
  160. be.be_arRot[im].ar_qRot.ToMatrix(mat);
  161. DecomposeRotationMatrixNoSnap(aangAngles[im],mat);
  162. }
  163. // try to remove rotations, steping by 2
  164. INDEX iloop=0;
  165. for(;iloop<ctfn;iloop++)
  166. {
  167. INDEX ctRemoved=0;
  168. // for each frame in bone envelope
  169. for(INDEX ifn=0;ifn<ctfn;ifn+=2)
  170. {
  171. INDEX iInd1 = FindNextFrame(ifn);
  172. INDEX iInd2 = FindNextFrame(iInd1+1);
  173. INDEX iInd3 = FindNextFrame(iInd2+1);
  174. // !!!! try only ind3
  175. if((iInd1 < 0)||(iInd2 < 0)||(iInd3 < 0)) break;
  176. AnimRot *parCurent = &be.be_arRot[iInd1];
  177. AnimRot *parNext = &be.be_arRot[iInd2];
  178. AnimRot *parLast = &be.be_arRot[iInd3];
  179. if(RemoveRotFrame(*parCurent,*parNext,*parLast,fTreshold))
  180. {
  181. aiRemFrameTable[iInd2] = TRUE;
  182. ctRemoved++;
  183. }
  184. }
  185. if(ctRemoved==0)
  186. {
  187. // exit if no keyframe has been removed
  188. break;
  189. }
  190. }
  191. // create temp array for rotations that are not removed
  192. CStaticStackArray<struct AnimRot> arRot;
  193. // for each removed frame
  194. for(INDEX ifnr=0;ifnr<ctfn;ifnr++)
  195. {
  196. // if frame is not in table for removed frames add it to temp arRot array
  197. if(!aiRemFrameTable[ifnr])
  198. {
  199. AnimRot &ar = arRot.Push();
  200. ar = be.be_arRot[ifnr];
  201. }
  202. }
  203. // count frames that are left
  204. INDEX ctfl = arRot.Count();
  205. // create new array for bone envelope
  206. be.be_arRot.Clear();
  207. be.be_arRot.New(ctfl);
  208. // copy array of rotaions
  209. INDEX fl=0;
  210. for(;fl<ctfl;fl++)
  211. {
  212. be.be_arRot[fl] = arRot[fl];
  213. }
  214. arRot.Clear();
  215. // do same thing for positions
  216. // clear table for removed frames
  217. memset(&aiRemFrameTable[0],0,sizeof(BOOL)*ctfn);
  218. // try to remove translations steping by 2
  219. for(iloop=0;iloop<ctfn;iloop++)
  220. {
  221. INDEX ctRemoved=0;
  222. for(INDEX ifn=0;ifn<ctfn;ifn+=2)
  223. {
  224. INDEX iInd1 = FindNextFrame(ifn);
  225. INDEX iInd2 = FindNextFrame(iInd1+1);
  226. INDEX iInd3 = FindNextFrame(iInd2+1);
  227. // !!!! try only ind3
  228. if((iInd1 < 0)||(iInd2 < 0)||(iInd3 < 0)) break;
  229. AnimPos *papCurent = &be.be_apPos[iInd1];
  230. AnimPos *papNext = &be.be_apPos[iInd2];
  231. AnimPos *papLast = &be.be_apPos[iInd3];
  232. if(RemovePosFrame(*papCurent,*papNext,*papLast,fTreshold))
  233. {
  234. aiRemFrameTable[iInd2] = TRUE;
  235. ctRemoved++;
  236. }
  237. }
  238. if(ctRemoved==0)
  239. {
  240. // exit if no keyframe has been removed
  241. break;
  242. }
  243. }
  244. CStaticStackArray<struct AnimPos> apPos;
  245. // count removed frames
  246. for(INDEX ifr=0;ifr<ctfn;ifr++)
  247. {
  248. if(!aiRemFrameTable[ifr])
  249. {
  250. AnimPos &ap = apPos.Push();
  251. ap = be.be_apPos[ifr];
  252. }
  253. }
  254. // count frames that are left
  255. ctfl = apPos.Count();
  256. // create new array for bone envelope
  257. be.be_apPos.Clear();
  258. be.be_apPos.New(ctfl);
  259. // copy array of translations
  260. for(fl=0;fl<ctfl;fl++)
  261. {
  262. be.be_apPos[fl] = apPos[fl];
  263. }
  264. apPos.Clear();
  265. }
  266. aiRemFrameTable.Clear();
  267. // if morph envelope has all factors 0 remove it
  268. CStaticStackArray<struct MorphEnvelope> aMorphs;
  269. INDEX ctme = an.an_ameMorphs.Count();
  270. for(INDEX ime=0;ime<ctme;ime++)
  271. {
  272. MorphEnvelope &me = an.an_ameMorphs[ime];
  273. // morph factors count
  274. INDEX ctwm=me.me_aFactors.Count();
  275. // index of wertex morph
  276. INDEX iwm=0;
  277. BOOL bMorphIsZero = TRUE;
  278. while(bMorphIsZero)
  279. {
  280. if(iwm>=ctwm) break;
  281. FLOAT &fMorphFactor = me.me_aFactors[iwm];
  282. // check if morph factor is 0
  283. bMorphIsZero = fMorphFactor == 0;
  284. iwm++;
  285. }
  286. // dont remove this morph envelope
  287. if(!bMorphIsZero)
  288. {
  289. // copy this morphmap to temp array of morph envelopes
  290. MorphEnvelope &meNew = aMorphs.Push();
  291. meNew = me;
  292. }
  293. }
  294. INDEX ctmeNew = aMorphs.Count();
  295. // crate new array for morph envelopes
  296. an.an_ameMorphs.Clear();
  297. an.an_ameMorphs.New(ctmeNew);
  298. // copy morph back to animations array of morph envelopes
  299. for(INDEX imeNew=0;imeNew<ctmeNew;imeNew++)
  300. {
  301. an.an_ameMorphs[imeNew] = aMorphs[imeNew];
  302. }
  303. }
  304. // add animation to animset
  305. void CAnimSet::AddAnimation(Animation *pan)
  306. {
  307. INDEX ctan = as_Anims.Count();
  308. as_Anims.Expand(ctan+1);
  309. Animation &an = as_Anims[ctan];
  310. an = *pan;
  311. }
  312. // remove animation from animset
  313. void CAnimSet::RemoveAnimation(Animation *pan)
  314. {
  315. INDEX ctan = as_Anims.Count();
  316. ASSERT(ctan>0);
  317. ASSERT(pan!=NULL);
  318. // copy all animations to temp array
  319. CStaticArray<struct Animation> animsTemp;
  320. animsTemp.New(ctan-1);
  321. INDEX ianNew=0;
  322. for(INDEX ian=0;ian<ctan;ian++)
  323. {
  324. Animation *panTemp = &as_Anims[ian];
  325. if(panTemp != pan)
  326. {
  327. // copy anims
  328. animsTemp[ianNew] = *panTemp;
  329. ianNew++;
  330. }
  331. }
  332. as_Anims = animsTemp;
  333. }
  334. // write to stream
  335. void CAnimSet::Write_t(CTStream *ostrFile)
  336. {
  337. // write id
  338. ostrFile->WriteID_t(CChunkID(ANIMSET_ID));
  339. // write version
  340. (*ostrFile)<<(INDEX)ANIMSET_VERSION;
  341. INDEX ctan = as_Anims.Count();
  342. (*ostrFile)<<ctan;
  343. for(int ian=0;ian<ctan;ian++)
  344. {
  345. Animation &an = as_Anims[ian];
  346. CTString pstrNameID = ska_GetStringFromTable(an.an_iID);
  347. // write anim source file
  348. (*ostrFile)<<an.an_fnSourceFile;
  349. // write anim id
  350. (*ostrFile)<<pstrNameID;
  351. // write secperframe
  352. (*ostrFile)<<an.an_fSecPerFrame;
  353. // write num of frames
  354. (*ostrFile)<<an.an_iFrames;
  355. // write treshold
  356. (*ostrFile)<<an.an_fTreshold;
  357. // write if compresion is used
  358. (*ostrFile)<<an.an_bCompresed;
  359. // write bool if animstion uses custom speed
  360. (*ostrFile)<<an.an_bCustomSpeed;
  361. INDEX ctbe = an.an_abeBones.Count();
  362. INDEX ctme = an.an_ameMorphs.Count();
  363. // write bone envelopes count
  364. (*ostrFile)<<ctbe;
  365. // for each bone envelope
  366. for(int ibe=0;ibe<ctbe;ibe++)
  367. {
  368. BoneEnvelope &be = an.an_abeBones[ibe];
  369. CTString pstrNameID = ska_GetStringFromTable(be.be_iBoneID);
  370. // write bone envelope ID
  371. (*ostrFile)<<pstrNameID;
  372. // write default pos(matrix12)
  373. ostrFile->Write_t(&be.be_mDefaultPos[0],sizeof(FLOAT)*12);
  374. // count positions
  375. INDEX ctp = be.be_apPos.Count();
  376. // write position count
  377. (*ostrFile)<<ctp;
  378. // for each position
  379. for(INDEX ip=0;ip<ctp;ip++)
  380. {
  381. // write position
  382. ostrFile->Write_t(&be.be_apPos[ip],sizeof(AnimPos));
  383. }
  384. // count rotations
  385. INDEX ctRotations = be.be_arRot.Count();
  386. (*ostrFile)<<ctRotations;
  387. // for each rotation
  388. for(INDEX ir=0;ir<ctRotations;ir++)
  389. {
  390. // write rotation
  391. AnimRot &arRot = be.be_arRot[ir];
  392. ostrFile->Write_t(&arRot,sizeof(AnimRot));
  393. }
  394. INDEX ctOptRotations = be.be_arRotOpt.Count();
  395. if(ctOptRotations>0)
  396. {
  397. // OPTIMISED ROTATIONS ARE NOT SAVED !!!
  398. // use RememberUnCompresedRotatations();
  399. ASSERT(ctRotations>=ctOptRotations);
  400. }
  401. // write offsetlen
  402. (*ostrFile)<<be.be_OffSetLen;
  403. }
  404. // write morph envelopes
  405. (*ostrFile)<<ctme;
  406. for(int ime=0;ime<ctme;ime++)
  407. {
  408. MorphEnvelope &me = an.an_ameMorphs[ime];
  409. CTString pstrNameID = ska_GetStringFromTable(me.me_iMorphMapID);
  410. // write morph map ID
  411. (*ostrFile)<<pstrNameID;
  412. // write morph factors count
  413. INDEX ctmf = me.me_aFactors.Count();
  414. (*ostrFile)<<ctmf;
  415. ostrFile->Write_t(&me.me_aFactors[0],sizeof(FLOAT)*ctmf);
  416. }
  417. }
  418. }
  419. // read from stream
  420. void CAnimSet::Read_t(CTStream *istrFile)
  421. {
  422. INDEX iFileVersion;
  423. // read chunk id
  424. istrFile->ExpectID_t(CChunkID(ANIMSET_ID));
  425. // check file version
  426. (*istrFile)>>iFileVersion;
  427. if(iFileVersion != ANIMSET_VERSION)
  428. {
  429. ThrowF_t(TRANS("File '%s'.\nInvalid animset file version. Expected Ver \"%d\" but found \"%d\"\n"),
  430. (const char*)istrFile->GetDescription(),ANIMSET_VERSION,iFileVersion);
  431. }
  432. INDEX ctan;
  433. // read anims count
  434. (*istrFile)>>ctan;
  435. // create anims array
  436. as_Anims.New(ctan);
  437. for(int ian=0;ian<ctan;ian++)
  438. {
  439. Animation &an = as_Anims[ian];
  440. CTString pstrNameID;
  441. // read anim source file
  442. (*istrFile)>>an.an_fnSourceFile;
  443. // read Anim ID
  444. (*istrFile>>pstrNameID);
  445. an.an_iID = ska_GetIDFromStringTable(pstrNameID);
  446. // read secperframe
  447. (*istrFile)>>an.an_fSecPerFrame;
  448. // read num of frames
  449. (*istrFile)>>an.an_iFrames;
  450. // read treshold
  451. (*istrFile)>>an.an_fTreshold;
  452. // read if compresion is used
  453. (*istrFile)>>an.an_bCompresed;
  454. // read bool if animstion uses custom speed
  455. (*istrFile)>>an.an_bCustomSpeed;
  456. INDEX ctbe;
  457. INDEX ctme;
  458. // read bone envelopes count
  459. (*istrFile)>>ctbe;
  460. // create bone envelopes array
  461. an.an_abeBones.New(ctbe);
  462. // read bone envelopes
  463. for(int ibe=0;ibe<ctbe;ibe++)
  464. {
  465. BoneEnvelope &be = an.an_abeBones[ibe];
  466. CTString pstrNameID;
  467. (*istrFile)>>pstrNameID;
  468. // read bone envelope ID
  469. be.be_iBoneID = ska_GetIDFromStringTable(pstrNameID);
  470. // read default pos(matrix12)
  471. istrFile->Read_t(&be.be_mDefaultPos[0],sizeof(FLOAT)*12);
  472. INDEX ctp;
  473. // read pos array
  474. (*istrFile)>>ctp;
  475. be.be_apPos.New(ctp);
  476. for(INDEX ip=0;ip<ctp;ip++)
  477. {
  478. istrFile->Read_t(&be.be_apPos[ip],sizeof(AnimPos));
  479. }
  480. INDEX ctr;
  481. // read rot array count
  482. (*istrFile)>>ctr;
  483. if(!an.an_bCompresed)
  484. {
  485. // create array for uncompresed rotations
  486. be.be_arRot.New(ctr);
  487. }
  488. else
  489. {
  490. // if flag is set to remember uncompresed rotations
  491. if(bAllRotations)
  492. {
  493. // create array for uncompresed rotations
  494. be.be_arRot.New(ctr);
  495. }
  496. // create array for compresed rotations
  497. be.be_arRotOpt.New(ctr);
  498. }
  499. for(INDEX ir=0;ir<ctr;ir++)
  500. {
  501. AnimRot arRot;// = be.be_arRot[ir];
  502. istrFile->Read_t(&arRot,sizeof(AnimRot));
  503. if(!an.an_bCompresed)
  504. {
  505. be.be_arRot[ir] = arRot;
  506. }
  507. else
  508. {
  509. if(bAllRotations)
  510. {
  511. // fill uncompresed rotations
  512. be.be_arRot[ir] = arRot;
  513. }
  514. // optimize quaternions
  515. FLOAT3D vAxis;
  516. ANGLE aAngle;
  517. UWORD ubH,ubP;
  518. FLOATquat3D &qRot = arRot.ar_qRot;
  519. AnimRotOpt &aroRot = be.be_arRotOpt[ir];
  520. qRot.ToAxisAngle(vAxis,aAngle);
  521. CompressAxis(vAxis,ubH,ubP);
  522. // compress angle
  523. aroRot.aro_aAngle = aAngle * ANG_COMPRESIONMUL;
  524. aroRot.aro_iFrameNum = arRot.ar_iFrameNum;
  525. aroRot.aro_ubH = ubH;
  526. aroRot.aro_ubP = ubP;
  527. be.be_arRotOpt[ir] = aroRot;
  528. }
  529. }
  530. // read offsetlen
  531. (*istrFile)>>be.be_OffSetLen;
  532. }
  533. // read morph envelopes
  534. (*istrFile)>>ctme;
  535. // create morph envelopes array
  536. an.an_ameMorphs.New(ctme);
  537. // read morph envelopes
  538. for(int ime=0;ime<ctme;ime++)
  539. {
  540. MorphEnvelope &me = an.an_ameMorphs[ime];
  541. CTString pstrNameID;
  542. // read morph envelope ID
  543. (*istrFile)>>pstrNameID;
  544. me.me_iMorphMapID = ska_GetIDFromStringTable(pstrNameID);
  545. INDEX ctmf;
  546. // read morph factors count
  547. (*istrFile)>>ctmf;
  548. // create morph factors array
  549. me.me_aFactors.New(ctmf);
  550. // read morph factors
  551. istrFile->Read_t(&me.me_aFactors[0],sizeof(FLOAT)*ctmf);
  552. }
  553. }
  554. }
  555. // clear animset
  556. void CAnimSet::Clear(void)
  557. {
  558. INDEX ctAnims = as_Anims.Count();
  559. for(INDEX iAnims=0;iAnims<ctAnims;iAnims++)
  560. {
  561. Animation &an = as_Anims[iAnims];
  562. INDEX ctBoneEnv = an.an_abeBones.Count();
  563. INDEX ctMorphEnv = an.an_ameMorphs.Count();
  564. for(INDEX iBoneEnv=0;iBoneEnv<ctBoneEnv;iBoneEnv++)
  565. {
  566. BoneEnvelope &be = an.an_abeBones[iBoneEnv];
  567. //be.be_aqvPlacement.Clear();
  568. be.be_apPos.Clear();
  569. be.be_arRot.Clear();
  570. }
  571. for(INDEX iMorphEnv=0;iMorphEnv<ctMorphEnv;iMorphEnv++)
  572. {
  573. MorphEnvelope &me = an.an_ameMorphs[iMorphEnv];
  574. me.me_aFactors.Clear();
  575. }
  576. an.an_abeBones.Clear();
  577. an.an_ameMorphs.Clear();
  578. }
  579. as_Anims.Clear();
  580. }
  581. // Count used memory
  582. SLONG CAnimSet::GetUsedMemory(void)
  583. {
  584. SLONG slMemoryUsed = sizeof(*this);
  585. INDEX ctAnims = as_Anims.Count();
  586. for(INDEX ias=0;ias<ctAnims;ias++) {
  587. Animation &an = as_Anims[ias];
  588. slMemoryUsed+=sizeof(an);
  589. // for each bone envelope
  590. INDEX ctbe = an.an_abeBones.Count();
  591. for(INDEX ibe=0;ibe<ctbe;ibe++) {
  592. BoneEnvelope &be = an.an_abeBones[ibe];
  593. slMemoryUsed+=sizeof(be);
  594. slMemoryUsed+=be.be_apPos.Count() * sizeof(AnimPos);
  595. slMemoryUsed+=be.be_arRot.Count() * sizeof(AnimRot);
  596. slMemoryUsed+=be.be_arRotOpt.Count() * sizeof(AnimRotOpt);
  597. }
  598. // for each morph envelope
  599. INDEX ctme = an.an_ameMorphs.Count();
  600. for(INDEX ime=0;ime<ctme;ime++) {
  601. MorphEnvelope &me = an.an_ameMorphs[ime];
  602. slMemoryUsed+=sizeof(me);
  603. slMemoryUsed+=sizeof(FLOAT) * me.me_aFactors.Count() + 12;
  604. }
  605. }
  606. return slMemoryUsed;
  607. }