GLS.FileMS3D.pas 30 KB

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