GLFileMS3D.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. Support for MS3D file format.
  6. }
  7. unit GLFileMS3D;
  8. interface
  9. {$I GLScene.inc}
  10. uses
  11. System.Math,
  12. System.Classes,
  13. System.SysUtils,
  14. GLVectorFileObjects,
  15. GLVectorTypes,
  16. GLMaterial,
  17. GLColor,
  18. GLTexture,
  19. GLVectorGeometry,
  20. GLVectorLists,
  21. GLApplicationFileIO;
  22. const
  23. MAX_MS3D_VERTICES = 8192;
  24. MAX_MS3D_TRIANGLES = 16384;
  25. MAX_MS3D_GROUPS = 128;
  26. MAX_MS3D_MATERIALS = 128;
  27. MAX_MS3D_JOINTS = 128;
  28. MAX_MS3D_KEYFRAMES = 5000;
  29. type
  30. // typedef struct
  31. // {
  32. // byte flags; // SELECTED | HIDDEN
  33. // char name[32]; //
  34. // word numtriangles; //
  35. // word triangleIndices[numtriangles]; // the groups group the triangles
  36. // char materialIndex; // -1 = no material
  37. // } ms3d_group_t;
  38. TMS3DGroup = class
  39. public
  40. Flags: byte;
  41. Name: array[0..31] of AnsiChar;
  42. NumTriangles: word;
  43. TriangleIndices: TList;
  44. MaterialIndex: Shortint;
  45. constructor Create;
  46. destructor Destroy; override;
  47. end;
  48. // typdef struct
  49. // {
  50. // char id[10]; // always "MS3D000000"
  51. // int version; // 4
  52. // } ms3d_header_t;
  53. {$A-}
  54. TMS3DHeader = record
  55. ID: array[0..9] of AnsiChar;
  56. Version: integer;
  57. end;
  58. // typedef struct
  59. // {
  60. // byte flags; // SELECTED | SELECTED2 | HIDDEN
  61. // float vertex[3]; //
  62. // char boneId; // -1 = no bone
  63. // byte referenceCount;
  64. // } ms3d_vertex_t;
  65. TMS3DVertex = record
  66. Flags: byte;
  67. Vertex: TD3DVector;
  68. BoneId: AnsiChar;
  69. ReferenceCount: byte;
  70. end;
  71. PMS3DVertexArray = ^TMS3DVertexArray;
  72. TMS3DVertexArray = array[0..MAX_MS3D_VERTICES - 1] of TMS3DVertex;
  73. // typedef struct
  74. // {
  75. // word flags; // SELECTED | SELECTED2 | HIDDEN
  76. // word vertexIndices[3]; //
  77. // float vertexNormals[3][3]; //
  78. // float s[3]; //
  79. // float t[3]; //
  80. // byte smoothingGroup; // 1 - 32
  81. // byte groupIndex; //
  82. // } ms3d_triangle_t;
  83. TMS3DTriangle = record
  84. Flags: word;
  85. VertexIndices: array[0..2] of word;
  86. VertexNormals: array[0..2] of TD3DVector;
  87. S: array[0..2] of single;
  88. T: array[0..2] of single;
  89. SmoothingGroup: byte; // 1 - 32
  90. GroupIndex: byte;
  91. end;
  92. PMS3DTriangleArray = ^TMS3DTriangleArray;
  93. TMS3DTriangleArray = array[0..MAX_MS3D_TRIANGLES - 1] of TMS3DTriangle;
  94. // typedef struct
  95. // {
  96. // char name[32]; //
  97. // float ambient[4]; //
  98. // float diffuse[4]; //
  99. // float specular[4]; //
  100. // float emissive[4]; //
  101. // float shininess; // 0.0f - 128.0f
  102. // float transparency; // 0.0f - 1.0f
  103. // char mode; // 0, 1, 2 is unused now
  104. // char texture[128]; // texture.bmp
  105. // char alphamap[128]; // alpha.bmp
  106. // } ms3d_material_t;
  107. TMS3DMaterial = record
  108. Name: array[0..31] of AnsiChar;
  109. Ambient: TColorVector;
  110. Diffuse: TColorVector;
  111. Specular: TColorVector;
  112. Emissive: TColorVector;
  113. Shininess: single;
  114. Transparency: single;
  115. Mode: AnsiChar;
  116. Texture: array[0..127] of AnsiChar;
  117. Alphamap: array[0..127] of AnsiChar;
  118. end;
  119. // typedef struct
  120. // {
  121. // float time; // time in seconds
  122. // float rotation[3]; // x, y, z angles
  123. // } ms3d_keyframe_rot_t;
  124. TMS3DKeyframeRotation = record
  125. Time: single;
  126. Rotation: TD3DVector;
  127. end;
  128. PMS3DKeyframeRotationArray = ^TMS3DKeyframeRotationArray;
  129. TMS3DKeyframeRotationArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframeRotation;
  130. // typedef struct
  131. // {
  132. // float time; // time in seconds
  133. // float position[3]; // local position
  134. // } ms3d_keyframe_pos_t;
  135. TMS3DKeyframePosition = record
  136. Time: single;
  137. Position: TD3DVector;
  138. end;
  139. PMS3DKeyframePositionArray = ^TMS3DKeyframePositionArray;
  140. TMS3DKeyframePositionArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframePosition;
  141. // typedef struct
  142. // {
  143. // byte flags; // SELECTED | DIRTY
  144. // char name[32]; //
  145. // char parentName[32]; //
  146. // float rotation[3]; // local reference matrix
  147. // float position[3];
  148. //
  149. // word numKeyFramesRot; //
  150. // word numKeyFramesTrans; //
  151. //
  152. // ms3d_keyframe_rot_t keyFramesRot[numKeyFramesRot]; // local animation matrices
  153. // ms3d_keyframe_pos_t keyFramesTrans[numKeyFramesTrans]; // local animation matrices
  154. // } ms3d_joint_t;
  155. TMS3DJointBase = record
  156. Flags: byte;
  157. Name: array[0..31] of AnsiChar;
  158. ParentName: array[0..31] of AnsiChar;
  159. Rotation: TD3DVector;
  160. Position: TD3DVector;
  161. NumKeyFramesRot: word;
  162. NumKeyFramesTrans: word;
  163. end;
  164. TMS3DJoint = record
  165. Base : TMS3DJointBase;
  166. KeyFramesRot: PMS3DKeyframeRotationArray;
  167. KeyFramesTrans: PMS3DKeyframePositionArray;
  168. end;
  169. PMS3DJointArray = ^TMS3DJointArray;
  170. TMS3DJointArray = array[0..MAX_MS3D_JOINTS - 1] of TMS3DJoint;
  171. TMS3DComment=record
  172. index: Integer;
  173. commentLength: integer;
  174. comment: array of AnsiChar;
  175. end;
  176. pMS3DComment=^TMS3DComment;
  177. TMS3DCommentList=class(TList)
  178. private
  179. protected
  180. public
  181. destructor Destroy; override;
  182. function NewComment: pMS3DComment;
  183. end;
  184. TMS3D_vertex_ex_t=record
  185. boneIds: array[0..2] of byte;
  186. weights: array[0..2] of byte;
  187. extra: cardinal;
  188. unknown: cardinal;
  189. end;
  190. pMS3D_vertex_ex_t=^TMS3D_vertex_ex_t;
  191. TVertexWeightList=class(TList)
  192. private
  193. FsubVersion: Integer;
  194. function GetWeight(idx: Integer): pMS3D_vertex_ex_t;
  195. procedure SetsubVersion(const Value: Integer);
  196. protected
  197. public
  198. function newWeight: pMS3D_vertex_ex_t;
  199. procedure Clear; override;
  200. destructor Destroy; override;
  201. property Weight[idx: Integer]: pMS3D_vertex_ex_t read GetWeight;
  202. property subVersion: Integer read FsubVersion write SetsubVersion;
  203. end;
  204. type
  205. { The MilkShape vector file.
  206. By Mattias Fagerlund, [email protected]. Yada yada. Eric rules! }
  207. TGLMS3DVectorFile = class(TGLVectorFile)
  208. public
  209. class function Capabilities: TGLDataFileCapabilities; override;
  210. procedure LoadFromStream(aStream: TStream); override;
  211. end;
  212. {$A+}
  213. // ------------------------------------------------------------------
  214. implementation
  215. { TMS3DGroup }
  216. constructor TMS3DGroup.Create;
  217. begin
  218. TriangleIndices := TList.Create;
  219. end;
  220. destructor TMS3DGroup.Destroy;
  221. begin
  222. TriangleIndices.Free;
  223. inherited;
  224. end;
  225. { TMS3DCommentList }
  226. destructor TMS3DCommentList.destroy;
  227. var
  228. i: integer;
  229. comment: pMS3DComment;
  230. begin
  231. for i:=0 to count-1 do begin
  232. comment:=items[i];
  233. comment^.comment:=nil;
  234. dispose(comment);
  235. end;
  236. inherited;
  237. end;
  238. function TMS3DCommentList.NewComment: pMS3DComment;
  239. begin
  240. new(result);
  241. add(result);
  242. end;
  243. { TVertexWeightList }
  244. procedure TVertexWeightList.clear;
  245. var
  246. i: integer;
  247. begin
  248. for i:=0 to count-1 do Dispose(Weight[i]);
  249. inherited;
  250. end;
  251. destructor TVertexWeightList.destroy;
  252. begin
  253. clear;
  254. inherited;
  255. end;
  256. function TVertexWeightList.GetWeight(idx: Integer): pMS3D_vertex_ex_t;
  257. begin
  258. result:=pMS3D_vertex_ex_t(items[idx]);
  259. end;
  260. function TVertexWeightList.newWeight: pMS3D_vertex_ex_t;
  261. var
  262. p: pMS3D_vertex_ex_t;
  263. begin
  264. new(p);
  265. add(p);
  266. result:=p;
  267. end;
  268. procedure TVertexWeightList.SetsubVersion(const Value: Integer);
  269. begin
  270. FsubVersion := Value;
  271. end;
  272. { TGLMS3DVectorFile }
  273. class function TGLMS3DVectorFile.Capabilities: TGLDataFileCapabilities;
  274. begin
  275. Result := [dfcRead];
  276. end;
  277. procedure TGLMS3DVectorFile.LoadFromStream(aStream: TStream);
  278. var
  279. // GLScene
  280. i, j, k: integer;
  281. itemp: Cardinal;
  282. wtemp: word;
  283. TexCoordID: integer;
  284. MO: TMeshObject;
  285. FaceGroup: TFGVertexNormalTexIndexList;
  286. Sk_MO: TGLSkeletonMeshObject;
  287. GroupList: TList;
  288. GLLibMaterial: TGLLibMaterial;
  289. // Milkshape 3d
  290. ms3d_header: TMS3DHeader;
  291. nNumVertices: word;
  292. ms3d_vertices: PMS3DVertexArray;
  293. nNumTriangles: word;
  294. ms3d_triangle: TMS3DTriangle;
  295. ms3d_triangle2: TMS3DTriangle;
  296. ms3d_triangles: PMS3DTriangleArray;
  297. nNumGroups: word;
  298. Group: TMS3DGroup;
  299. nNumMaterials: word;
  300. ms3d_material: TMS3DMaterial;
  301. fAnimationFPS: single;
  302. fCurrentTime: single;
  303. iTotalFrames: integer;
  304. nNumJoints: word;
  305. ms3d_joints: PMS3DJointArray;
  306. bonelist: TStringList;
  307. bone: TGLSkeletonBone;
  308. frame: TGLSkeletonFrame;
  309. rot, pos: TVector3f;
  310. //Tod
  311. subVersionComments: integer;
  312. subVersionVertexExtra: integer;
  313. nNumGroupComments: integer;
  314. nNumMaterialComments: integer;
  315. nNumJointComments: integer;
  316. nHasModelComment: integer;
  317. ms3d_comment: pMS3DComment;
  318. vertexWeight: pMS3D_vertex_ex_t;
  319. ms3d_norm_Array: array of TD3DVector;
  320. ms3d_norm: TD3DVector;
  321. path, libtexture: string;
  322. dotpos: Integer;
  323. //Helper classes for MS3D comments if you want to use them.
  324. groupCommentList: TMS3DCommentList;
  325. materialCommentList: TMS3DCommentList;
  326. jointCommentList: TMS3DCommentList;
  327. modelCommentList: TMS3DCommentList;
  328. procedure AddFaceVertex(ID: integer);
  329. begin
  330. // Add the texCoord
  331. TexCoordID := MO.TexCoords.Add(ms3d_triangle.s[ID], -ms3d_triangle.t[ID]);
  332. //Ok, here we add the vertex and the normal. We pass in the vertex index for both the vertex and the normal.
  333. // This is because we have already added the normals to the Mesh in the same order as the vertices.
  334. FaceGroup.Add(ms3d_triangle.vertexIndices[ID], ms3d_triangle.vertexIndices[ID], TexCoordID);
  335. end;
  336. function AddRotations(rot, baserot: TAffineVector): TAffineVector;
  337. var
  338. mat1, mat2, rmat: TMatrix;
  339. s, c: Single;
  340. Trans: TTransformations;
  341. begin
  342. mat1 := IdentityHMGMatrix;
  343. mat2 := IdentityHMGMatrix;
  344. SinCos(rot.X, s, c);
  345. rmat := CreateRotationMatrixX(s, c);
  346. mat1 := MatrixMultiply(mat1, rmat);
  347. SinCos(rot.Y, s, c);
  348. rmat := CreateRotationMatrixY(s, c);
  349. mat1 := MatrixMultiply(mat1, rmat);
  350. SinCos(rot.Z, s, c);
  351. rmat := CreateRotationMatrixZ(s, c);
  352. mat1 := MatrixMultiply(mat1, rmat);
  353. SinCos(baserot.X, s, c);
  354. rmat := CreateRotationMatrixX(s, c);
  355. mat2 := MatrixMultiply(mat2, rmat);
  356. SinCos(baserot.Y, s, c);
  357. rmat := CreateRotationMatrixY(s, c);
  358. mat2 := MatrixMultiply(mat2, rmat);
  359. SinCos(baserot.Z, s, c);
  360. rmat := CreateRotationMatrixZ(s, c);
  361. mat2 := MatrixMultiply(mat2, rmat);
  362. mat1 := MatrixMultiply(mat1, mat2);
  363. if MatrixDecompose(mat1, Trans) then
  364. SetVector(Result, Trans[ttRotateX], Trans[ttRotateY], Trans[ttRotateZ])
  365. else
  366. Result := NullVector;
  367. end;
  368. begin
  369. GroupList := TList.Create;
  370. FaceGroup := nil;
  371. ms3d_vertices := nil;
  372. ms3d_triangles := nil;
  373. ms3d_joints := nil;
  374. ms3d_norm_Array := nil;
  375. groupCommentList := nil;
  376. materialCommentList := nil;
  377. jointCommentList := nil;
  378. modelCommentList := nil;
  379. try
  380. //Save the path of the MS3D so we can load the texture from that location instead of the EXE location.
  381. path := ExtractFilePath(ResourceName);
  382. if Length(path)>0 then
  383. path := IncludeTrailingPathDelimiter( path );
  384. // First comes the header.
  385. aStream.ReadBuffer(ms3d_header, sizeof(TMS3DHeader));
  386. Assert(ms3d_header.version = 4, Format('The MilkShape3D importer can only handle MS3D files of version 4, this is version ', [ms3d_header.id]));
  387. // Then comes the number of vertices
  388. aStream.ReadBuffer(nNumVertices, sizeof(nNumVertices));
  389. // Creates the vertex list
  390. if Owner is TGLActor then
  391. begin
  392. MO := TGLSkeletonMeshObject.CreateOwned(Owner.MeshObjects);
  393. TGLSkeletonMeshObject(MO).BonesPerVertex := 4;
  394. end
  395. else
  396. MO := TMeshObject.CreateOwned(Owner.MeshObjects);
  397. MO.Mode := momFaceGroups;
  398. // Then comes nNumVertices * sizeof (ms3d_vertex_t)
  399. ms3d_vertices := AllocMem(sizeof(TMS3DVertex) * nNumVertices);
  400. aStream.ReadBuffer(ms3d_vertices^, sizeof(TMS3DVertex) * nNumVertices);
  401. for i := 0 to nNumVertices - 1 do
  402. with ms3d_vertices^[i] do
  403. begin
  404. // Add the vertex to the vertexlist
  405. MO.Vertices.Add(vertex.v);
  406. if Owner is TGLActor then
  407. TGLSkeletonMeshObject(MO).AddWeightedBone(Byte(BoneID), 1);
  408. end;
  409. // number of triangles
  410. aStream.ReadBuffer(nNumTriangles, sizeof(nNumTriangles));
  411. // nNumTriangles * sizeof (ms3d_triangle_t)
  412. ms3d_triangles := AllocMem(sizeof(TMS3DTriangle) * nNumTriangles);
  413. aStream.ReadBuffer(ms3d_triangles^, sizeof(TMS3DTriangle) * nNumTriangles);
  414. // Now we have to match up the vertices with the normals that are in the triangles list
  415. // This is because Milkshape stores normals in the triangles group. A vertex can be used
  416. // many times by different faces. We need to compress that down to 1 vertex = 1 normal
  417. ms3d_norm.X := 0;
  418. ms3d_norm.Y := 0;
  419. ms3d_norm.Z := 0;
  420. setLength(ms3d_norm_Array, nNumVertices);
  421. for i := 0 to nNumVertices - 1 do
  422. ms3d_norm_Array[i] := ms3d_norm;
  423. for i := 0 to nNumTriangles - 1 do
  424. begin
  425. ms3d_triangle2 := ms3d_triangles^[i];
  426. ms3d_norm_Array[ms3d_triangle2.VertexIndices[0]] := ms3d_triangle2.VertexNormals[0];
  427. ms3d_norm_Array[ms3d_triangle2.VertexIndices[1]] := ms3d_triangle2.VertexNormals[1];
  428. ms3d_norm_Array[ms3d_triangle2.VertexIndices[2]] := ms3d_triangle2.VertexNormals[2];
  429. end;
  430. // Now add the normals in the same order as the vertices to the mesh
  431. for i := 0 to nNumVertices - 1 do
  432. begin
  433. MO.Normals.Add(ms3d_norm_Array[i].v);
  434. end;
  435. ms3d_norm_Array := nil;
  436. // number of groups
  437. aStream.ReadBuffer(nNumGroups, sizeof(nNumGroups));
  438. // nNumGroups * sizeof (ms3d_group_t)
  439. for i := 0 to nNumGroups - 1 do
  440. begin
  441. // Read the first part of the group
  442. Group := TMS3DGroup.Create;
  443. GroupList.Add(Group);
  444. aStream.ReadBuffer(Group.Flags, sizeof(Group.Flags));
  445. aStream.ReadBuffer(Group.name, sizeof(Group.name));
  446. aStream.ReadBuffer(Group.numtriangles, sizeof(Group.numtriangles));
  447. for j := 0 to Group.numtriangles - 1 do
  448. begin
  449. aStream.ReadBuffer(wtemp, sizeof(wtemp));
  450. itemp := wtemp;
  451. Group.triangleIndices.Add(pointer(itemp));
  452. end;
  453. aStream.ReadBuffer(Group.materialIndex, sizeof(Group.materialIndex));
  454. // if materialindex=-1, then there is no material, and all faces should
  455. // be added to a base VIL
  456. if Group.materialIndex = -1 then
  457. begin
  458. // If there's no base VIL, create one!
  459. if FaceGroup = nil then
  460. FaceGroup := TFGVertexNormalTexIndexList.CreateOwned(MO.FaceGroups);
  461. for j := 0 to Group.numtriangles - 1 do
  462. begin
  463. ms3d_triangle := ms3d_triangles^[Cardinal(Group.triangleIndices[j])];
  464. AddFaceVertex(0);
  465. AddFaceVertex(1);
  466. AddFaceVertex(2);
  467. end;
  468. end;
  469. end;
  470. // number of materials
  471. aStream.ReadBuffer(nNumMaterials, sizeof(nNumMaterials));
  472. // nNumMaterials * sizeof (ms3d_material_t)
  473. for i := 0 to nNumMaterials - 1 do
  474. begin
  475. aStream.ReadBuffer(ms3d_material, sizeof(TMS3DMaterial));
  476. // Creates the material, if there's a materiallibrary!
  477. if Assigned(Owner.MaterialLibrary) then
  478. begin
  479. libtexture := string(ms3d_material.texture);
  480. dotpos := System.Pos('.', libtexture);
  481. Delete(libtexture, dotpos, Length(libtexture)-dotpos+1);
  482. GLLibMaterial := Owner.MaterialLibrary.LibMaterialByName(libtexture);
  483. if Assigned(GLLibMaterial) then
  484. begin
  485. GLLibMaterial.Material.Texture.Disabled := False;
  486. end
  487. else if FileStreamExists(path + string(ms3d_material.texture)) then
  488. GLLibMaterial := Owner.MaterialLibrary.AddTextureMaterial(libtexture, path + string(ms3d_material.texture))
  489. else
  490. begin
  491. if not Owner.IgnoreMissingTextures then
  492. Exception.Create('Texture file not found: ' + path + string(ms3d_material.texture));
  493. GLLibMaterial := Owner.MaterialLibrary.Materials.Add;
  494. GLLibMaterial.Name := string(ms3d_material.name);
  495. end;
  496. GLLibMaterial.Material.FrontProperties.Emission.Color := ms3d_material.emissive;
  497. GLLibMaterial.Material.FrontProperties.Ambient.Color := ms3d_material.ambient;
  498. GLLibMaterial.Material.FrontProperties.Diffuse.Color := ms3d_material.diffuse;
  499. GLLibMaterial.Material.FrontProperties.Specular.Color := ms3d_material.specular;
  500. // Shinintess is 0 to 128 in both MS3D and GLScene. Why not 0 to 127? Odd.
  501. GLLibMaterial.Material.FrontProperties.Shininess := round(ms3d_material.shininess);
  502. // ms3d_material.transparency is allready set as alpha channel on all
  503. // colors above
  504. if ms3d_material.transparency < 1 then
  505. begin
  506. GLLibMaterial.Material.BlendingMode := bmTransparency;
  507. GLLibMaterial.Material.FaceCulling := fcNoCull; //Make transparent materials two sided.
  508. end;
  509. GLLibMaterial.Material.Texture.TextureMode := tmModulate;
  510. // Creates a new face group and add all triangles for this material
  511. // here. We must cycle through all groups that have this material
  512. FaceGroup := TFGVertexNormalTexIndexList.CreateOwned(MO.FaceGroups);
  513. FaceGroup.MaterialName := GLLibMaterial.Name;
  514. for j := 0 to GroupList.Count - 1 do
  515. begin
  516. Group := TMS3DGroup(GroupList[j]);
  517. if Group.materialIndex = i then
  518. for k := 0 to Group.numtriangles - 1 do
  519. begin
  520. ms3d_triangle := ms3d_triangles^[Cardinal(Group.triangleIndices[k])];
  521. AddFaceVertex(0);
  522. AddFaceVertex(1);
  523. AddFaceVertex(2);
  524. end;
  525. end;
  526. end
  527. else
  528. begin
  529. Exception.Create(ResourceName + ' has materials but there is no material library assigned to the object loading this MS3D file.' + #10#13 + 'If this is what you want, then you can safely ignore this exception.');
  530. end;
  531. end;
  532. // save some keyframer data
  533. aStream.ReadBuffer(fAnimationFPS, sizeof(fAnimationFPS));
  534. aStream.ReadBuffer(fCurrentTime, sizeof(fCurrentTime));
  535. aStream.ReadBuffer(iTotalFrames, sizeof(iTotalFrames));
  536. if Owner is TGLActor then
  537. begin
  538. TGLActor(Owner).Interval := trunc(1 / fAnimationFPS * 1000);
  539. end;
  540. // number of joints
  541. aStream.ReadBuffer(nNumJoints, sizeof(nNumJoints));
  542. // nNumJoints * sizeof (ms3d_joint_t)
  543. ms3d_joints := AllocMem(sizeof(TMS3DJoint) * nNumJoints);
  544. // We have to read the joints one by one!
  545. for i := 0 to nNumJoints - 1 do
  546. begin
  547. // Read the joint base
  548. aStream.ReadBuffer(ms3d_joints^[i].Base, sizeof(TMS3DJointBase));
  549. if (i = 0) then
  550. Assert(ms3d_joints^[i].base.numKeyFramesRot = iTotalFrames, 'This importer only works if the number of key frames = the number of total frames. i.e. Every frame must be a key frame');
  551. if ms3d_joints^[i].base.numKeyFramesRot > 0 then
  552. begin
  553. // Allocate memory for the rotations
  554. ms3d_joints^[i].keyFramesRot := AllocMem(sizeof(TMS3DKeyframeRotation) * ms3d_joints^[i].base.numKeyFramesRot);
  555. // Read the rotations
  556. aStream.ReadBuffer(ms3d_joints^[i].keyFramesRot^, sizeof(TMS3DKeyframeRotation) * ms3d_joints^[i].base.numKeyFramesRot);
  557. end
  558. else
  559. ms3d_joints^[i].keyFramesRot := nil;
  560. if ms3d_joints^[i].base.numKeyFramesTrans > 0 then
  561. begin
  562. // Allocate memory for the translations
  563. ms3d_joints^[i].keyFramesTrans := AllocMem(sizeof(TMS3DKeyframePosition) * ms3d_joints^[i].base.numKeyFramesTrans);
  564. // Read the translations
  565. aStream.ReadBuffer(ms3d_joints^[i].keyFramesTrans^, sizeof(TMS3DKeyframePosition) * ms3d_joints^[i].base.numKeyFramesTrans);
  566. end
  567. else
  568. ms3d_joints^[i].keyFramesTrans := nil;
  569. end;
  570. //Below is the Comments sections. We don't do anything with them at all. Only read in for future use if needed
  571. aStream.ReadBuffer(subVersionComments, sizeof(subVersionComments));
  572. //*******************
  573. //* now read in the Group Comments.
  574. //*******************
  575. aStream.ReadBuffer(nNumGroupComments, sizeof(nNumGroupComments));
  576. groupCommentList := TMS3DCommentList.Create;
  577. if (nNumGroupComments > 0) then
  578. groupCommentList.Capacity := nNumGroupComments;
  579. for i := 0 to nNumGroupComments - 1 do
  580. begin
  581. ms3d_comment := groupCommentList.NewComment;
  582. aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
  583. aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
  584. setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
  585. aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
  586. end;
  587. ////////
  588. //*******************
  589. //* now read in the Material Comments.
  590. //*******************
  591. aStream.ReadBuffer(nNumMaterialComments, sizeof(nNumMaterialComments));
  592. MaterialCommentList := TMS3DCommentList.Create;
  593. if (nNumMaterialComments > 0) then
  594. MaterialCommentList.Capacity := nNumMaterialComments;
  595. for i := 0 to nNumMaterialComments - 1 do
  596. begin
  597. ms3d_comment := MaterialCommentList.NewComment;
  598. aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
  599. aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
  600. setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
  601. aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
  602. end;
  603. ////////
  604. //*******************
  605. //* now read in the Joint Comments.
  606. //*******************
  607. aStream.ReadBuffer(nNumJointComments, sizeof(nNumJointComments));
  608. JointCommentList := TMS3DCommentList.Create;
  609. if (nNumJointComments > 0) then
  610. JointCommentList.Capacity := nNumJointComments;
  611. for i := 0 to nNumJointComments - 1 do
  612. begin
  613. ms3d_comment := JointCommentList.NewComment;
  614. aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
  615. aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
  616. setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
  617. aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
  618. end;
  619. ////////
  620. //*******************
  621. //* now read in the Model Comment (if any). The milkshape spec on this is somewhat wrong, as it does not use the same
  622. //* comments structure as the previous ones. Index is not included and I guess is assumed to always be 0 as there
  623. //* can only be one
  624. //*******************
  625. aStream.ReadBuffer(nHasModelComment, sizeof(nHasModelComment));
  626. ModelCommentList := TMS3DCommentList.Create;
  627. for i := 0 to nHasModelComment - 1 do
  628. begin
  629. ms3d_comment := ModelCommentList.NewComment;
  630. ms3d_comment^.index := 0;
  631. aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
  632. setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
  633. aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
  634. end;
  635. ////////
  636. //Read in the vertex weights
  637. //
  638. aStream.ReadBuffer(subVersionVertexExtra, sizeof(subVersionVertexExtra));
  639. Sk_MO := TGLSkeletonMeshObject(MO);
  640. if Owner is TGLActor then
  641. begin
  642. for i := 0 to nNumVertices - 1 do
  643. begin
  644. new(vertexWeight);
  645. aStream.ReadBuffer(vertexWeight^.boneIds[0], sizeOf(vertexWeight^.boneIds));
  646. aStream.ReadBuffer(vertexWeight^.weights[0], sizeOf(vertexWeight^.weights));
  647. aStream.ReadBuffer(vertexWeight^.extra, sizeOf(vertexWeight^.extra));
  648. if (subVersionVertexExtra = 3) then
  649. aStream.ReadBuffer(vertexWeight^.unknown, sizeOf(vertexWeight^.unknown));
  650. Sk_MO.VerticesBonesWeights^[i]^[0].Weight := 1;
  651. if (vertexWeight.boneIds[0] <> 255) then
  652. begin
  653. Sk_MO.VerticesBonesWeights^[i]^[0].Weight := vertexWeight.weights[0] / 100;
  654. Sk_MO.VerticesBonesWeights^[i]^[1].Weight := vertexWeight.weights[1] / 100;
  655. Sk_MO.VerticesBonesWeights^[i]^[1].BoneID := vertexWeight.boneIds[0];
  656. end
  657. else
  658. begin
  659. Sk_MO.VerticesBonesWeights^[i]^[1].Weight := 0;
  660. Sk_MO.VerticesBonesWeights^[i]^[1].BoneID := 0;
  661. end;
  662. if (vertexWeight.boneIds[1] <> 255) then
  663. begin
  664. Sk_MO.VerticesBonesWeights^[i]^[2].Weight := vertexWeight.weights[2] / 100;
  665. Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := vertexWeight.boneIds[1];
  666. end
  667. else
  668. begin
  669. Sk_MO.VerticesBonesWeights^[i]^[2].Weight := 0;
  670. Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := 0;
  671. end;
  672. if (vertexWeight.boneIds[2] <> 255) then
  673. begin
  674. Sk_MO.VerticesBonesWeights^[i]^[3].Weight := 1.0 - (vertexWeight.weights[0] + vertexWeight.weights[1] + vertexWeight.weights[2]) / 100;
  675. Sk_MO.VerticesBonesWeights^[i]^[3].BoneID := vertexWeight.boneIds[2];
  676. end
  677. else
  678. begin
  679. Sk_MO.VerticesBonesWeights^[i]^[3].Weight := 0;
  680. Sk_MO.VerticesBonesWeights^[i]^[3].BoneID := 0;
  681. end;
  682. dispose(vertexWeight);
  683. end;
  684. end;
  685. // ***
  686. // Mesh Transformation:
  687. //
  688. // 0. Build the transformation matrices from the rotation and position
  689. // 1. Multiply the vertices by the inverse of local reference matrix (lmatrix0)
  690. // 2. then translate the result by (lmatrix0 * keyFramesTrans)
  691. // 3. then multiply the result by (lmatrix0 * keyFramesRot)
  692. //
  693. // For normals skip step 2.
  694. //
  695. //
  696. //
  697. // NOTE: this file format may change in future versions!
  698. //
  699. //
  700. // - Mete Ciragan
  701. // ***
  702. if (Owner is TGLActor) and (nNumJoints > 0) then
  703. begin
  704. // Bone names are added to a list initally to sort out parents
  705. bonelist := TStringList.Create;
  706. for i := 0 to nNumJoints - 1 do
  707. bonelist.Add(string(ms3d_joints^[i].Base.Name));
  708. // Find parent bones and add their children
  709. for i := 0 to nNumJoints - 1 do
  710. begin
  711. j := bonelist.IndexOf(string(ms3d_joints^[i].Base.ParentName));
  712. if j = -1 then
  713. bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones)
  714. else
  715. bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones.BoneByID(j));
  716. bone.Name := string(ms3d_joints^[i].Base.Name);
  717. bone.BoneID := i;
  718. end;
  719. bonelist.Free;
  720. // Set up the base pose
  721. frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames);
  722. for i := 0 to nNumJoints - 1 do
  723. begin
  724. pos := ms3d_joints^[i].Base.Position.V;
  725. rot := ms3d_joints^[i].Base.Rotation.V;
  726. frame.Position.Add(pos);
  727. frame.Rotation.Add(rot);
  728. end;
  729. // Now load the animations
  730. for i := 0 to nNumJoints - 1 do
  731. begin
  732. for j := 0 to ms3d_joints^[i].Base.NumKeyFramesRot - 1 do
  733. begin
  734. if (j + 1) = Owner.Skeleton.Frames.Count then
  735. frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames)
  736. else
  737. frame := Owner.Skeleton.Frames[j + 1];
  738. if ms3d_joints^[i].Base.ParentName = '' then
  739. begin
  740. pos := ms3d_joints^[i].KeyFramesTrans^[j].Position.V;
  741. //pos:=ms3d_joints^[i].Base.Position.V;
  742. rot := ms3d_joints^[i].KeyFramesRot^[j].Rotation.V;
  743. end
  744. else
  745. begin
  746. pos := ms3d_joints^[i].KeyFramesTrans^[0].Position.V; //Always read tranlation position from the first frame
  747. AddVector(pos, ms3d_joints^[i].Base.Position.V);
  748. rot := ms3d_joints^[i].KeyFramesRot^[j].Rotation.V;
  749. rot := AddRotations(rot, ms3d_joints^[i].Base.Rotation.V);
  750. end;
  751. frame.Position.Add(pos);
  752. frame.Rotation.Add(rot);
  753. end;
  754. end;
  755. Owner.Skeleton.RootBones.PrepareGlobalMatrices;
  756. TGLSkeletonMeshObject(MO).PrepareBoneMatrixInvertedMeshes;
  757. with TGLActor(Owner).Animations.Add do
  758. begin
  759. Reference := aarSkeleton;
  760. StartFrame := 0;
  761. EndFrame := Owner.Skeleton.Frames.Count;
  762. end;
  763. end;
  764. finally
  765. if Assigned(ms3d_vertices) then
  766. FreeMem(ms3d_vertices);
  767. if Assigned(ms3d_triangles) then
  768. FreeMem(ms3d_triangles);
  769. if Assigned(ms3d_joints) then
  770. begin
  771. // Free the internal storage of the joint
  772. for i := 0 to nNumJoints - 1 do
  773. begin
  774. if Assigned(ms3d_joints^[i].keyFramesRot) then
  775. FreeMem(ms3d_joints^[i].keyFramesRot);
  776. if Assigned(ms3d_joints^[i].keyFramesTrans) then
  777. FreeMem(ms3d_joints^[i].keyFramesTrans);
  778. end;
  779. FreeMem(ms3d_joints);
  780. end;
  781. // Finalize
  782. for i := 0 to GroupList.Count - 1 do
  783. TMS3DGroup(GroupList[i]).Free;
  784. GroupList.Free;
  785. if (assigned(groupCommentList)) then
  786. groupCommentList.free;
  787. if (assigned(materialCommentList)) then
  788. materialCommentList.free;
  789. if (assigned(jointCommentList)) then
  790. jointCommentList.free;
  791. if (assigned(modelCommentList)) then
  792. modelCommentList.free;
  793. end;
  794. end;
  795. // ------------------------------------------------------------------
  796. initialization
  797. // ------------------------------------------------------------------
  798. RegisterVectorFileFormat('ms3d', 'MilkShape3D files', TGLMS3DVectorFile);
  799. end.