Skeleton.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 "Skeleton.h"
  14. #include <Engine/Graphics/DrawPort.h>
  15. #include <Engine/Math/Projection.h>
  16. #include <Engine/Ska/StringTable.h>
  17. #include <Engine/Ska/Render.h>
  18. #include <Engine/Base/Stream.h>
  19. #include <Engine/Templates/DynamicContainer.cpp>
  20. #define SKELETON_VERSION 6
  21. #define SKELETON_ID "SKEL"
  22. CStaticArray<struct SkeletonBone> _aSortArray;
  23. INDEX ctSortBones;
  24. CSkeleton::CSkeleton()
  25. {
  26. }
  27. CSkeleton::~CSkeleton()
  28. {
  29. }
  30. // Find bone in skeleton lod
  31. INDEX CSkeleton::FindBoneInLOD(INDEX iBoneID,INDEX iSkeletonLod)
  32. {
  33. ASSERT(iSkeletonLod>=0);
  34. INDEX ctslods = skl_aSkeletonLODs.Count();
  35. if(ctslods < 1) return -1;
  36. SkeletonLOD &slod = skl_aSkeletonLODs[iSkeletonLod];
  37. INDEX ctb = slod.slod_aBones.Count();
  38. // for each bone in skeleton
  39. for(INDEX isb=0;isb<ctb;isb++) {
  40. // if bone id match
  41. if(slod.slod_aBones[isb].sb_iID == iBoneID) {
  42. // return index in array of bones
  43. return isb;
  44. }
  45. }
  46. return -1;
  47. }
  48. // Sorts bones in skeleton so parent bones are allways before child bones in array
  49. void CSkeleton::SortSkeleton()
  50. {
  51. // sort each lod in skeleton
  52. INDEX ctslods = skl_aSkeletonLODs.Count();
  53. // for each lod in skeleton
  54. for(INDEX islod=0;islod<ctslods;islod++)
  55. {
  56. // create SkeletonBones array for sorting array
  57. _aSortArray.New(skl_aSkeletonLODs[islod].slod_aBones.Count());
  58. // start sort for parent bone
  59. SortSkeletonRecursive(-1,islod);
  60. // just copy sorted array
  61. skl_aSkeletonLODs[islod].slod_aBones.CopyArray(_aSortArray);
  62. // clear array
  63. _aSortArray.Clear();
  64. // calculate abs transforms for bones in this lod
  65. CalculateAbsoluteTransformations(islod);
  66. }
  67. }
  68. // Sort skeleton bones in lod so parent bones are before child bones in array
  69. void CSkeleton::SortSkeletonRecursive(INDEX iParentID, INDEX iSkeletonLod)
  70. {
  71. // reset global counter for sorted bones if this bone is parent bone
  72. if(iParentID == (-1)) ctSortBones = 0;
  73. SkeletonLOD &slod = skl_aSkeletonLODs[iSkeletonLod];
  74. INDEX ctsb = slod.slod_aBones.Count();
  75. // for each bone in lod
  76. for(INDEX isb=0;isb<ctsb;isb++)
  77. {
  78. SkeletonBone &sb = slod.slod_aBones[isb];
  79. if(sb.sb_iParentID == iParentID)
  80. {
  81. // just copy data to _aSortArray
  82. _aSortArray[ctSortBones].sb_iID = sb.sb_iID;
  83. _aSortArray[ctSortBones].sb_iParentID = sb.sb_iParentID;
  84. _aSortArray[ctSortBones].sb_fBoneLength = sb.sb_fBoneLength;
  85. memcpy(&_aSortArray[ctSortBones].sb_mAbsPlacement,&sb.sb_mAbsPlacement,sizeof(float)*12);
  86. memcpy(&_aSortArray[ctSortBones].sb_qvRelPlacement,&sb.sb_qvRelPlacement,sizeof(QVect));
  87. _aSortArray[ctSortBones].sb_fOffSetLen = sb.sb_fOffSetLen;
  88. // increase couter for sorted bones
  89. ctSortBones++;
  90. }
  91. }
  92. // sort children bones
  93. for(INDEX icsb=0;icsb<ctsb;icsb++) {
  94. SkeletonBone &sb = slod.slod_aBones[icsb];
  95. if(sb.sb_iParentID == iParentID) {
  96. SortSkeletonRecursive(sb.sb_iID,iSkeletonLod);
  97. }
  98. }
  99. }
  100. // Calculate absolute transformations for all bones in this lod
  101. void CSkeleton::CalculateAbsoluteTransformations(INDEX iSkeletonLod)
  102. {
  103. INDEX ctbones = skl_aSkeletonLODs[iSkeletonLod].slod_aBones.Count();
  104. SkeletonLOD &slod = skl_aSkeletonLODs[iSkeletonLod];
  105. // for each bone
  106. for(INDEX isb=0; isb<ctbones; isb++) {
  107. SkeletonBone &sb = slod.slod_aBones[isb];
  108. INDEX iParentID = sb.sb_iParentID;
  109. INDEX iParentIndex = FindBoneInLOD(iParentID,iSkeletonLod);
  110. if(iParentID > (-1)) {
  111. SkeletonBone &sbParent = slod.slod_aBones[iParentIndex];
  112. MatrixMultiplyCP(sb.sb_mAbsPlacement,sbParent.sb_mAbsPlacement,sb.sb_mAbsPlacement);
  113. }
  114. }
  115. }
  116. // Add skeleton lod to skeleton
  117. void CSkeleton::AddSkletonLod(SkeletonLOD &slod)
  118. {
  119. INDEX ctlods = skl_aSkeletonLODs.Count();
  120. skl_aSkeletonLODs.Expand(ctlods+1);
  121. skl_aSkeletonLODs[ctlods] = slod;
  122. }
  123. // Remove skleton lod form skeleton
  124. void CSkeleton::RemoveSkeletonLod(SkeletonLOD *pslodRemove)
  125. {
  126. INDEX ctslod = skl_aSkeletonLODs.Count();
  127. // create temp space for skeleton lods
  128. CStaticArray<struct SkeletonLOD> aTempSLODs;
  129. aTempSLODs.New(ctslod-1);
  130. INDEX iIndexSrc=0;
  131. // for each skeleton lod in skeleton
  132. for(INDEX islod=0;islod<ctslod;islod++) {
  133. SkeletonLOD *pslod = &skl_aSkeletonLODs[islod];
  134. // copy all skeleton lods except the selected one
  135. if(pslod != pslodRemove) {
  136. aTempSLODs[iIndexSrc] = *pslod;
  137. iIndexSrc++;
  138. }
  139. }
  140. // copy temp array of skeleton lods back in skeleton
  141. skl_aSkeletonLODs.CopyArray(aTempSLODs);
  142. // clear temp skleletons lods array
  143. aTempSLODs.Clear();
  144. }
  145. // write to stream
  146. void CSkeleton::Write_t(CTStream *ostrFile)
  147. {
  148. INDEX ctslods = skl_aSkeletonLODs.Count();
  149. // write id
  150. ostrFile->WriteID_t(CChunkID(SKELETON_ID));
  151. // write version
  152. (*ostrFile)<<(INDEX)SKELETON_VERSION;
  153. // write lods count
  154. (*ostrFile)<<ctslods;
  155. // for each lod in skeleton
  156. for(INDEX islod=0;islod<ctslods;islod++)
  157. {
  158. SkeletonLOD &slod = skl_aSkeletonLODs[islod];
  159. // write source file name
  160. (*ostrFile)<<slod.slod_fnSourceFile;
  161. // write MaxDistance
  162. (*ostrFile)<<slod.slod_fMaxDistance;
  163. // write bone count
  164. INDEX ctb = slod.slod_aBones.Count();
  165. (*ostrFile)<<ctb;
  166. // write skeleton bones
  167. for(INDEX ib=0;ib<ctb;ib++) {
  168. CTString strNameID = ska_GetStringFromTable(slod.slod_aBones[ib].sb_iID);
  169. CTString strParentID = ska_GetStringFromTable(slod.slod_aBones[ib].sb_iParentID);
  170. SkeletonBone &sb = slod.slod_aBones[ib];
  171. // write ID
  172. (*ostrFile)<<strNameID;
  173. // write Parent ID
  174. (*ostrFile)<<strParentID;
  175. //(*ostrFile)<<slod.slod_aBones[ib].sb_iParentIndex;
  176. // write AbsPlacement matrix
  177. ostrFile->Write_t(&sb.sb_mAbsPlacement,sizeof(FLOAT)*12);
  178. // write RelPlacement Qvect stuct
  179. ostrFile->Write_t(&sb.sb_qvRelPlacement,sizeof(QVect));
  180. // write offset len
  181. (*ostrFile)<<sb.sb_fOffSetLen;
  182. // write bone length
  183. (*ostrFile)<<sb.sb_fBoneLength;
  184. }
  185. }
  186. }
  187. // read from stream
  188. void CSkeleton::Read_t(CTStream *istrFile)
  189. {
  190. INDEX iFileVersion;
  191. INDEX ctslods;
  192. // read chunk id
  193. istrFile->ExpectID_t(CChunkID(SKELETON_ID));
  194. // check file version
  195. (*istrFile)>>iFileVersion;
  196. if(iFileVersion != SKELETON_VERSION) {
  197. ThrowF_t(TRANS("File '%s'.\nInvalid skeleton file version.\nExpected Ver \"%d\" but found \"%d\"\n"),
  198. (const char*)istrFile->GetDescription(),SKELETON_VERSION,iFileVersion);
  199. }
  200. // read skeleton lod count
  201. (*istrFile)>>ctslods;
  202. if(ctslods>0) {
  203. skl_aSkeletonLODs.Expand(ctslods);
  204. }
  205. // for each skeleton lod
  206. for(INDEX islod=0;islod<ctslods;islod++) {
  207. SkeletonLOD &slod = skl_aSkeletonLODs[islod];
  208. // read source file name
  209. (*istrFile)>>slod.slod_fnSourceFile;
  210. // read MaxDistance
  211. (*istrFile)>>slod.slod_fMaxDistance;
  212. // read bone count
  213. INDEX ctb;
  214. (*istrFile)>>ctb;
  215. // create bone array
  216. slod.slod_aBones.New(ctb);
  217. // read skeleton bones
  218. for(INDEX ib=0;ib<ctb;ib++) {
  219. CTString strNameID;
  220. CTString strParentID;
  221. SkeletonBone &sb = slod.slod_aBones[ib];
  222. // read ID
  223. (*istrFile)>>strNameID;
  224. // read Parent ID
  225. (*istrFile)>>strParentID;
  226. //(*istrFile)>>slod.slod_aBones[ib].sb_iParentIndex ;
  227. sb.sb_iID = ska_GetIDFromStringTable(strNameID);
  228. sb.sb_iParentID = ska_GetIDFromStringTable(strParentID);
  229. // read AbsPlacement matrix
  230. istrFile->Read_t(&sb.sb_mAbsPlacement,sizeof(FLOAT)*12);
  231. // read RelPlacement Qvect stuct
  232. istrFile->Read_t(&sb.sb_qvRelPlacement,sizeof(QVect));
  233. // read offset len
  234. (*istrFile)>>sb.sb_fOffSetLen;
  235. // read bone length
  236. (*istrFile)>>sb.sb_fBoneLength;
  237. }
  238. }
  239. }
  240. // Clear skeleton
  241. void CSkeleton::Clear(void)
  242. {
  243. // for each LOD
  244. for (INDEX islod=0; islod<skl_aSkeletonLODs.Count(); islod++) {
  245. // clear bones array
  246. skl_aSkeletonLODs[islod].slod_aBones.Clear();
  247. }
  248. // clear all lods
  249. skl_aSkeletonLODs.Clear();
  250. }
  251. // Count used memory
  252. SLONG CSkeleton::GetUsedMemory(void)
  253. {
  254. SLONG slMemoryUsed = sizeof(*this);
  255. INDEX ctslods = skl_aSkeletonLODs.Count();
  256. // for each skeleton lods
  257. for(INDEX islod=0;islod<ctslods;islod++) {
  258. SkeletonLOD &slod = skl_aSkeletonLODs[islod];
  259. slMemoryUsed += sizeof(slod);
  260. slMemoryUsed += slod.slod_aBones.Count() * sizeof(SkeletonBone);
  261. }
  262. return slMemoryUsed;
  263. }