FileGL2.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Ghoul2 (GLM/GLA) file format loading structures
  6. Note: Also referred to as MDX (MDXM/MDXA) format in C source.
  7. }
  8. unit FileGL2;
  9. interface
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. GLVectorTypes,
  14. GLVectorGeometry;
  15. type
  16. TGLMHeader = record
  17. fileID : array[0..3] of char;
  18. version : integer;
  19. strFile,
  20. animName : array[0..63] of char;
  21. animIndex,
  22. numBones,
  23. numLODs,
  24. ofsLODs,
  25. numSurfaces,
  26. ofsSurfHierarchy,
  27. ofsEnd : integer;
  28. end;
  29. TGLMSurfaceHeirachyOffsets = array of integer;
  30. TGLMSurfaceHeirachy = record
  31. name : array[0..63] of Char;
  32. flags : LongWord;
  33. shader : array[0..63] of Char;
  34. shaderIndex,
  35. parentIndex,
  36. numChildren : integer;
  37. childIndices : array of integer;
  38. end;
  39. TGLMSurfaceHeader = record
  40. ident,
  41. thisSurfaceIndex,
  42. ofsHeader,
  43. numVerts,
  44. ofsVerts,
  45. numTriangles,
  46. ofsTriangles,
  47. numBoneReferences,
  48. ofsBoneReferences,
  49. ofsEnd : integer;
  50. end;
  51. TGLMTriangle = record
  52. indices : array[0..2] of integer;
  53. end;
  54. TGLMVertex = record
  55. normal,
  56. vertex : TVector3f;
  57. uiNumWeightsAndBoneIndices : Cardinal; // packed int
  58. BoneWeightings : array[0..3] of Byte;
  59. end;
  60. TGLMSurface = record
  61. SurfaceHeader : TGLMSurfaceHeader;
  62. Triangles : array of TGLMTriangle;
  63. Vertices : array of TGLMVertex;
  64. TexCoords : array of TVector2f;
  65. BoneReferences : array of Integer;
  66. end;
  67. TGLMLODInfo = record
  68. ofsEnd : integer;
  69. end;
  70. TGLMLODSurfaceOffsets = array of integer;
  71. TGLMLODs = record
  72. LODInfo : TGLMLODInfo;
  73. LODSurfaceOffsets : TGLMLODSurfaceOffsets;
  74. Surfaces : array of TGLMSurface;
  75. end;
  76. TGLAHeader = record
  77. fileID : array[0..3] of char;
  78. version : integer;
  79. Name : array[0..63] of char;
  80. fScale : single;
  81. numFrames,
  82. ofsFrames,
  83. numBones,
  84. ofsCompBonePool,
  85. ofsSkel,
  86. ofsEnd : integer;
  87. end;
  88. TGLABone = array[0..2] of TVector4f;
  89. TGLACompQuatBone = array[0..6] of Word; {14 bytes}
  90. TGLASkeletonOffsets = array of integer;
  91. TGLASkeleton = record
  92. name : array[0..63] of char;
  93. flags : LongWord;
  94. parent : Integer;
  95. BasePoseMat,
  96. BasePoseMatInv : TGLABone;
  97. numChildren : Integer;
  98. children : array of Integer;
  99. end;
  100. // Ghoul2 Model structure
  101. TFileGLM = class
  102. public
  103. ModelHeader : TGLMHeader;
  104. SurfaceHeirachyOffsets : TGLMSurfaceHeirachyOffsets;
  105. SurfaceHeirachy : array of TGLMSurfaceHeirachy;
  106. LODs : array of TGLMLODs;
  107. procedure LoadFromStream(aStream : TStream);
  108. end;
  109. // Ghoul2 Animation structure
  110. TFileGLA = class
  111. public
  112. AnimHeader : TGLAHeader;
  113. SkeletonOffsets : TGLASkeletonOffsets;
  114. Skeleton : array of TGLASkeleton;
  115. BoneIndices : array of Integer;
  116. CompBonePool : array of TGLACompQuatBone;
  117. function GetCompressedMatrix(Frame,Bone : Integer):TGLACompQuatBone;
  118. function GetUnCompressedMatrix(Frame,Bone : Integer):TMatrix;
  119. procedure LoadFromStream(aStream : TStream);
  120. end;
  121. function G2_GetVertWeights(const vert:TGLMVertex):Integer;
  122. function G2_GetVertBoneIndex(const vert:TGLMVertex; iWeightNum:Integer):Integer;
  123. function G2_GetVertBoneWeight(const vert:TGLMVertex; iWeightNum:Cardinal;
  124. var fTotalWeight:Single; const iNumWeights:Cardinal):single;
  125. procedure MC_UnCompressQuat(var mat : TMatrix; const comp : TGLACompQuatBone);
  126. // ------------------------------------------------------------------
  127. implementation
  128. // ------------------------------------------------------------------
  129. // ------------------
  130. // ------------------ Misc routines ------------------
  131. // ------------------
  132. // Adapted from mdx_format.h
  133. // static inline int G2_GetVertWeights( const mdxmVertex_t *pVert )
  134. // static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWeightNum)
  135. // static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights )
  136. function G2_GetVertWeights(const vert:TGLMVertex):Integer;
  137. begin
  138. // Get number of bones per vertex (0..3)+1 = (1..4)
  139. result:=(vert.uiNumWeightsAndBoneIndices shr 30)+1;
  140. end;
  141. function G2_GetVertBoneIndex(const vert:TGLMVertex; iWeightNum:Integer):Integer;
  142. begin
  143. // Extract the bone reference array index, a 5-bit integer
  144. result:=(vert.uiNumWeightsAndBoneIndices shr (5*iWeightNum)) and 31;
  145. end;
  146. function G2_GetVertBoneWeight(const vert:TGLMVertex; iWeightNum:Cardinal;
  147. var fTotalWeight:Single; const iNumWeights:Cardinal):single;
  148. var
  149. fBoneWeight : Single;
  150. iTemp : Cardinal;
  151. begin
  152. if (iWeightNum = iNumWeights-1) then begin
  153. // No need to calculate final weight value, return the
  154. // weight left over out of 1
  155. fBoneWeight:=1-fTotalWeight;
  156. end else begin
  157. // Get the initial 8-bit bone weight
  158. iTemp:=vert.BoneWeightings[iWeightNum];
  159. // Get the 2-bit overflow and 'or' it to the front of the
  160. // weight to get 10-bit integer weight (0..1023)
  161. iTemp:=iTemp or ((vert.uiNumWeightsAndBoneIndices shr (12+(iWeightNum*2))) and $300);
  162. // Convert to floating point weight (0..1)
  163. fBoneWeight:=iTemp/1023;
  164. // Accumulate total weight
  165. fTotalWeight:=fTotalWeight+fBoneWeight;
  166. end;
  167. Result:=fBoneWeight;
  168. end;
  169. // Adapted from matcomp.c
  170. // void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp)
  171. procedure MC_UnCompressQuat(var mat : TMatrix; const comp : TGLACompQuatBone);
  172. begin
  173. mat:=QuaternionToMatrix(QuaternionMake([comp[1]-32726,comp[2]-32726,comp[3]-32726],comp[0]-32726));
  174. mat.V[3]:=VectorMake(comp[4]/64-512,comp[5]/64-512,comp[6]/64-512,1);
  175. end;
  176. // ------------------
  177. // ------------------ TFileGLM ------------------
  178. // ------------------
  179. procedure TFileGLM.LoadFromStream(aStream: TStream);
  180. var
  181. idstr : array[0..3] of char;
  182. i,j : integer;
  183. ofs,
  184. LODofs : int64;
  185. begin
  186. aStream.Read(idstr,sizeof(idstr));
  187. aStream.Position:=0;
  188. if not (idstr='2LGM') then begin
  189. raise Exception.Create(Format('Unknown or incorrect identity tag: [%s]',[idstr]));
  190. exit;
  191. end;
  192. aStream.Read(ModelHeader,SizeOf(ModelHeader));
  193. if ModelHeader.version<>6 then
  194. raise Exception.Create(Format('Only GLM (MDXM) version 6 is supported. File is version %d.',[ModelHeader.version]));
  195. SetLength(SurfaceHeirachyOffsets,ModelHeader.numSurfaces);
  196. aStream.Read(SurfaceHeirachyOffsets[0],sizeof(Integer)*ModelHeader.numSurfaces);
  197. SetLength(SurfaceHeirachy,ModelHeader.numSurfaces);
  198. for i:=0 to ModelHeader.numSurfaces-1 do
  199. with SurfaceHeirachy[i] do begin
  200. aStream.Read(name,Length(name));
  201. aStream.Read(flags,sizeof(LongWord));
  202. aStream.Read(shader,Length(shader));
  203. aStream.Read(shaderindex,sizeof(Integer));
  204. aStream.Read(parentindex,sizeof(Integer));
  205. aStream.Read(numChildren,sizeof(Integer));
  206. if numChildren>0 then begin
  207. SetLength(childIndices,numChildren);
  208. aStream.Read(childIndices[0],numChildren*sizeof(Integer));
  209. end else SetLength(childIndices,0);
  210. end;
  211. SetLength(LODs,ModelHeader.numLODs);
  212. for i:=0 to ModelHeader.numLODs-1 do
  213. with LODs[i] do begin
  214. LODofs:=aStream.Position;
  215. aStream.Read(LODInfo,sizeof(LODInfo));
  216. SetLength(LODSurfaceOffsets,ModelHeader.numSurfaces);
  217. aStream.Read(LODSurfaceOffsets[0],sizeof(integer)*ModelHeader.numSurfaces);
  218. SetLength(Surfaces,ModelHeader.numSurfaces);
  219. for j:=0 to ModelHeader.numSurfaces-1 do
  220. with Surfaces[j] do begin
  221. ofs:=aStream.Position;
  222. aStream.Read(SurfaceHeader,SizeOf(TGLMSurfaceHeader));
  223. SetLength(Triangles,SurfaceHeader.numTriangles);
  224. SetLength(Vertices,SurfaceHeader.numVerts);
  225. SetLength(TexCoords,SurfaceHeader.numVerts);
  226. SetLength(BoneReferences,SurfaceHeader.numBoneReferences);
  227. aStream.Position:=ofs+SurfaceHeader.ofsTriangles;
  228. aStream.Read(Triangles[0],SurfaceHeader.numTriangles*SizeOf(TGLMTriangle));
  229. aStream.Position:=ofs+SurfaceHeader.ofsVerts;
  230. aStream.Read(Vertices[0],SurfaceHeader.numVerts*SizeOf(TGLMVertex));
  231. aStream.Read(TexCoords[0],SurfaceHeader.numVerts*SizeOf(TVector2f));
  232. aStream.Position:=ofs+SurfaceHeader.ofsBoneReferences;
  233. aStream.Read(BoneReferences[0],SurfaceHeader.numBoneReferences*SizeOf(Integer));
  234. aStream.Position:=ofs+SurfaceHeader.ofsEnd;
  235. end;
  236. aStream.Position:=LODofs+LODInfo.ofsEnd;
  237. end;
  238. end;
  239. // ------------------
  240. // ------------------ TFileGLA ------------------
  241. // ------------------
  242. function TFileGLA.GetCompressedMatrix(Frame, Bone: Integer): TGLACompQuatBone;
  243. begin
  244. Result:=CompBonePool[BoneIndices[Frame*AnimHeader.numBones+Bone]];
  245. end;
  246. // GetUnCompressedMatrix
  247. //
  248. function TFileGLA.GetUnCompressedMatrix(Frame, Bone: Integer): TMatrix;
  249. begin
  250. MC_UnCompressQuat(Result,CompBonePool[BoneIndices[Frame*AnimHeader.numBones+Bone]]);
  251. end;
  252. procedure TFileGLA.LoadFromStream(aStream: TStream);
  253. var
  254. idstr : array[0..3] of char;
  255. i,temp : integer;
  256. buf : array of array[0..2] of Byte;
  257. begin
  258. aStream.Read(idstr,sizeof(idstr));
  259. aStream.Position:=0;
  260. if not (idstr='2LGA') then begin
  261. raise Exception.Create(Format('Unknown or incorrect identity tag: [%s]',[idstr]));
  262. exit;
  263. end;
  264. aStream.Read(AnimHeader,SizeOf(AnimHeader));
  265. if AnimHeader.version<>6 then
  266. raise Exception.Create(Format('Only GLA (MDXA) version 6 is supported. File is version %d.',[AnimHeader.version]));
  267. SetLength(SkeletonOffsets,AnimHeader.numBones);
  268. aStream.Read(SkeletonOffsets[0],sizeof(Integer)*AnimHeader.numBones);
  269. SetLength(Skeleton,AnimHeader.numBones);
  270. for i:=0 to AnimHeader.numBones-1 do
  271. with Skeleton[i] do begin
  272. aStream.Read(name,Length(name));
  273. aStream.Read(flags,sizeof(LongWord));
  274. aStream.Read(Parent,SizeOf(Integer));
  275. aStream.Read(basePoseMat,sizeof(TGLABone));
  276. aStream.Read(basePoseMatInv,sizeof(TGLABone));
  277. aStream.Read(numChildren,sizeof(Integer));
  278. if numChildren>0 then begin
  279. SetLength(children,numChildren);
  280. aStream.Read(children[0],numChildren*sizeof(Integer));
  281. end else SetLength(children,0);
  282. end;
  283. aStream.Position:=AnimHeader.ofsFrames;
  284. SetLength(BoneIndices,AnimHeader.numFrames*AnimHeader.numBones);
  285. SetLength(buf,AnimHeader.numFrames*AnimHeader.numBones*3);
  286. aStream.Read(buf[0],AnimHeader.numFrames*AnimHeader.numBones*3);
  287. for i:=0 to AnimHeader.numFrames*AnimHeader.numBones-1 do
  288. BoneIndices[i]:=(buf[i][2] shl 16) or (buf[i][1] shl 8) or buf[i][0];
  289. SetLength(buf,0);
  290. aStream.Position:=AnimHeader.ofsCompBonePool;
  291. temp:=AnimHeader.ofsEnd-AnimHeader.ofsCompBonePool;
  292. SetLength(CompBonePool,temp div SizeOf(TGLACompQuatBone));
  293. aStream.Read(CompBonePool[0],temp);
  294. end;
  295. end.