GLFileLMTS.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. {
  5. File loader for MTS
  6. }
  7. unit GLFileLMTS;
  8. interface
  9. {$I GLScene.inc}
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. Vcl.Graphics,
  14. GLVectorTypes,
  15. GLVectorFileObjects,
  16. GLApplicationFileIO,
  17. GLVectorLists,
  18. GLVectorGeometry,
  19. GLTexture,
  20. GLPersistentClasses,
  21. GLGraphics,
  22. GLMaterial;
  23. const
  24. C_LMTS_ID = $53544D4C;
  25. C_LMTS_VER = 4;
  26. C_LMTS_SUBS = $53425553;
  27. C_LMTS_TEXT = $54584554;
  28. C_LMTS_TRIS = $53495254;
  29. C_LMTS_TEXFNLEN = 255; // max texture filename length
  30. type
  31. PLMTS_Header = ^TLMTS_Header;
  32. TLMTS_Header = record // packed
  33. ID: cardinal;
  34. Ver: cardinal;
  35. headerSize: cardinal;
  36. nTexts: word; // # of textures
  37. nSubsets: word;
  38. nTris: cardinal;
  39. subSize: word;
  40. vtxSize: word;
  41. end;
  42. PLMTS_TexData = ^TLMTS_TexData;
  43. TLMTS_TexData = record // packed
  44. fName: array [0 .. C_LMTS_TEXFNLEN] of AnsiChar;
  45. Flags: Word;
  46. end;
  47. PLMTS_Subset = ^TLMTS_Subset;
  48. TLMTS_Subset = record // packed
  49. Offset: LongInt;
  50. Count: LongInt;
  51. TextID1: Word;
  52. TextID2: Word;
  53. end;
  54. PLMTS_Vertex = ^TLMTS_Vertex;
  55. TLMTS_Vertex = record // packed
  56. x, y, z: Single;
  57. u1, v1, u2, v2: Single;
  58. end;
  59. PLMTS = ^TLMTS;
  60. TLMTS = record
  61. header: TLMTS_Header;
  62. usrData: pointer;
  63. usrSize: cardinal;
  64. texData: pointer;
  65. subsets: pointer;
  66. tris: pointer;
  67. ok: boolean;
  68. end;
  69. TMaterialInfo = record
  70. FShininess, BShininess: TGLShininess;
  71. FAmbient, FDiffuse, FEmission, FSpecular, BAmbient, BDiffuse, BEmission,
  72. BSpecular: TVector;
  73. ImageAlpha: TGLTextureImageAlpha;
  74. magFilter: TGLMagFilter;
  75. minFilter: TGLMinFilter;
  76. TextureMode: TGLTextureMode;
  77. TextureWrap: TGLTextureWrap;
  78. Blendingmode: TGLBlendingMode;
  79. FaceCulling: TGLFaceCulling;
  80. mathash: integer;
  81. end;
  82. TGLLMTSVectorFile = class(TGLVectorFile)
  83. public
  84. class function Capabilities: TGLDataFileCapabilities; override;
  85. procedure LoadFromStream(aStream: TStream); override;
  86. procedure SaveToStream(aStream: TStream); override;
  87. end;
  88. //---------------------------------------------------
  89. implementation
  90. //---------------------------------------------------
  91. uses
  92. GLTextureFormat;
  93. // ------------------
  94. // ------------------ TGLLMTSVectorFile ------------------
  95. // ------------------
  96. class function TGLLMTSVectorFile.Capabilities: TGLDataFileCapabilities;
  97. begin
  98. Result := [dfcRead, dfcWrite];
  99. end;
  100. procedure TGLLMTSVectorFile.LoadFromStream(aStream: TStream);
  101. var
  102. MO: TMeshObject;
  103. FG: TFGVertexIndexList;
  104. LL: TGLMaterialLibrary;
  105. ML: TGLMaterialLibrary;
  106. LMTS: TLMTS;
  107. T: TLMTS_TexData;
  108. V: array [0 .. 2] of TLMTS_Vertex;
  109. S: TLMTS_Subset;
  110. _4cc: Cardinal;
  111. C: Integer;
  112. fName: string;
  113. vi: Tintegerlist;
  114. libmat: TGLLibmaterial;
  115. lmnames, matnames: TStringlist;
  116. MatInfoHeader: array [0 .. 3] of AnsiChar;
  117. MatInfoCount: Cardinal;
  118. Matinfo: array of TMaterialInfo;
  119. i, j: Integer;
  120. begin
  121. owner.MeshObjects.Clear;
  122. MO := TMeshObject.CreateOwned(owner.MeshObjects);
  123. MO.Mode := momFaceGroups;
  124. vi := Tintegerlist.create;
  125. LL := owner.LightmapLibrary;
  126. ML := owner.MaterialLibrary;
  127. lmnames := TStringlist.create;
  128. matnames := TStringlist.create;
  129. MatInfoCount := 0;
  130. try
  131. // read header...
  132. aStream.Read(LMTS.header, SizeOf(TLMTS_Header));
  133. // verify...
  134. if (LMTS.header.ID <> C_LMTS_ID) or (LMTS.header.Ver <> C_LMTS_VER) or
  135. (LMTS.header.headerSize < SizeOf(TLMTS_Header)) or
  136. (LMTS.header.subSize < SizeOf(TLMTS_Subset)) or
  137. (LMTS.header.vtxSize < SizeOf(TLMTS_Vertex)) then
  138. raise Exception.create('Error in header');
  139. // read "user" data - actually skip this data...
  140. LMTS.usrSize := LMTS.header.headerSize - SizeOf(TLMTS_Header);
  141. if (LMTS.usrSize > 7) then
  142. begin
  143. aStream.Read(MatInfoHeader, 4);
  144. if MatInfoHeader = 'MATI' then
  145. begin
  146. aStream.Read(MatInfoCount, 4);
  147. if MatInfoCount > 0 then
  148. begin
  149. setlength(Matinfo, MatInfoCount);
  150. for i := 0 to MatInfoCount - 1 do
  151. begin
  152. aStream.Read(Matinfo[i], SizeOf(Matinfo[i]));
  153. end;
  154. end;
  155. if LMTS.usrSize > ((MatInfoCount * SizeOf(TMaterialInfo)) + 8) then
  156. begin
  157. LMTS.usrSize := LMTS.usrSize -
  158. ((MatInfoCount * SizeOf(TMaterialInfo)) + 8);
  159. aStream.Seek(LMTS.usrSize, soFromCurrent);
  160. end;
  161. end
  162. else
  163. aStream.Seek(LMTS.usrSize - 4, soFromCurrent);
  164. end
  165. else if (LMTS.usrSize > 0) then
  166. aStream.Seek(LMTS.usrSize, soFromCurrent);
  167. // read texture filenames data...
  168. aStream.Read(_4cc, SizeOf(_4cc));
  169. if (_4cc <> C_LMTS_TEXT) then
  170. raise Exception.create('Texture data not found');
  171. for C := 0 to LMTS.header.nTexts - 1 do
  172. begin
  173. aStream.Read(T, SizeOf(TLMTS_TexData));
  174. if T.Flags = 0 then
  175. begin
  176. if Assigned(ML) and (trim(String(T.fName)) <> '') then
  177. begin
  178. fName := String(T.fName);
  179. try
  180. if lastdelimiter('.', fName) <> length(fName) - 3 then
  181. fName := fName + '.tga'
  182. else
  183. fName := changefileext(fName, '.tga');
  184. if not fileexists(fName) then
  185. begin
  186. fName := changefileext(fName, '.jpg');
  187. if not fileexists(fName) then
  188. begin
  189. fName := changefileext(fName, '.png');
  190. if not fileexists(fName) then
  191. begin
  192. fName := changefileext(fName, '.bmp');
  193. if not fileexists(fName) then
  194. begin
  195. fName := changefileext(fName, '.dds');
  196. if not fileexists(fName) then
  197. begin
  198. fName := String(T.fName);
  199. end;
  200. // fName:=fName+' (missing)';
  201. end;
  202. end;
  203. end;
  204. end;
  205. libmat := ML.Materials.GetLibMaterialByName(fName);
  206. if not Assigned(libmat) then
  207. begin
  208. with ML.AddTextureMaterial(fName, fName) do
  209. Material.Texture.TextureMode := tmModulate;
  210. end;
  211. matnames.add(fName);
  212. except
  213. matnames.add(fName);
  214. { on E: ETexture do
  215. begin
  216. if not Owner.IgnoreMissingTextures then
  217. raise;
  218. end; }
  219. end;
  220. end
  221. else
  222. matnames.add(String(T.fName));
  223. end
  224. else
  225. begin
  226. if Assigned(LL) and (trim(String(T.fName)) <> '') then
  227. begin
  228. fName := String(T.fName);
  229. try
  230. if lastdelimiter('.', fName) <> length(fName) - 3 then
  231. fName := fName + '.tga'
  232. else
  233. fName := changefileext(fName, '.tga');
  234. if not fileexists(fName) then
  235. begin
  236. fName := changefileext(fName, '.jpg');
  237. if not fileexists(fName) then
  238. begin
  239. fName := changefileext(fName, '.png');
  240. if not fileexists(fName) then
  241. begin
  242. fName := changefileext(fName, '.bmp');
  243. if not fileexists(fName) then
  244. begin
  245. fName := changefileext(fName, '.dds');
  246. if not fileexists(fName) then
  247. begin
  248. fName := String(T.fName);
  249. end;
  250. // fName:=fName+' (missing)';
  251. end;
  252. end;
  253. end;
  254. end;
  255. libmat := LL.Materials.GetLibMaterialByName(fName);
  256. if not Assigned(libmat) then
  257. begin
  258. with LL.AddTextureMaterial(fName, fName).Material.Texture do
  259. begin
  260. minFilter := miLinear;
  261. TextureWrap := twNone;
  262. TextureFormat := tfRGB;
  263. TextureMode := tmModulate;
  264. end;
  265. end;
  266. lmnames.add(fName);
  267. except
  268. lmnames.add(fName);
  269. { on E: ETexture do
  270. begin
  271. if not Owner.IgnoreMissingTextures then
  272. raise;
  273. end; }
  274. end;
  275. end
  276. else
  277. lmnames.add(String(T.fName));
  278. end;
  279. end;
  280. if Assigned(owner.MaterialLibrary) then
  281. for i := 0 to MatInfoCount - 1 do
  282. begin
  283. libmat := nil;
  284. for j := 0 to owner.MaterialLibrary.Materials.Count - 1 do
  285. if owner.MaterialLibrary.Materials[j].NameHashKey = Matinfo[i].mathash
  286. then
  287. begin
  288. libmat := owner.MaterialLibrary.Materials[j];
  289. break;
  290. end;
  291. if Assigned(libmat) then
  292. begin
  293. with Matinfo[i] do
  294. begin
  295. libmat.Material.FrontProperties.Shininess := FShininess;
  296. libmat.Material.BackProperties.Shininess := BShininess;
  297. libmat.Material.FrontProperties.Ambient.Color := FAmbient;
  298. libmat.Material.FrontProperties.Diffuse.Color := FDiffuse;
  299. libmat.Material.FrontProperties.Emission.Color := FEmission;
  300. libmat.Material.FrontProperties.Specular.Color := FSpecular;
  301. libmat.Material.BackProperties.Ambient.Color := BAmbient;
  302. libmat.Material.BackProperties.Diffuse.Color := BDiffuse;
  303. libmat.Material.BackProperties.Emission.Color := BEmission;
  304. libmat.Material.BackProperties.Specular.Color := BSpecular;
  305. libmat.Material.Texture.ImageAlpha := ImageAlpha;
  306. libmat.Material.Texture.magFilter := magFilter;
  307. libmat.Material.Texture.minFilter := minFilter;
  308. libmat.Material.Texture.TextureMode := TextureMode;
  309. libmat.Material.Texture.TextureWrap := TextureWrap;
  310. libmat.Material.Blendingmode := Blendingmode;
  311. libmat.Material.FaceCulling := FaceCulling;
  312. end;
  313. end;
  314. end;
  315. // read subset data...
  316. aStream.Read(_4cc, SizeOf(_4cc));
  317. if (_4cc <> C_LMTS_SUBS) then
  318. raise Exception.create('Subset data not found');
  319. for C := LMTS.header.nSubsets - 1 downto 0 do
  320. begin
  321. aStream.Read(S, LMTS.header.subSize);
  322. FG := TFGVertexIndexList.CreateOwned(MO.FaceGroups);
  323. FG.Mode := fgmmTriangles;
  324. FG.vertexindices.AddSerie(S.Offset * 3, 1, S.Count * 3);
  325. vi.AddSerie(S.Offset * 3, 1, S.Count * 3);
  326. if Assigned(ML) and (S.TextID1 <> $FFFF) then
  327. begin
  328. if (S.TextID1 < matnames.Count) then
  329. begin
  330. libmat := ML.Materials.GetLibMaterialByName(matnames[S.TextID1]);
  331. if Assigned(libmat) then
  332. FG.MaterialName := libmat.Name;
  333. end;
  334. end;
  335. if Assigned(LL) and (S.TextID2 <> $FFFF) then
  336. begin
  337. if (S.TextID2 - matnames.Count < lmnames.Count) and
  338. (S.TextID2 - matnames.Count > -1) then
  339. begin
  340. libmat := LL.Materials.GetLibMaterialByName
  341. (lmnames[S.TextID2 - matnames.Count]);
  342. if Assigned(libmat) then
  343. FG.lightmapindex := libmat.Index;
  344. end;
  345. end;
  346. end;
  347. // read vertex data...
  348. aStream.Read(_4cc, SizeOf(_4cc));
  349. if (_4cc <> C_LMTS_TRIS) then
  350. raise Exception.create('Vertex data not found');
  351. for C := 0 to integer(LMTS.header.nTris) - 1 do
  352. begin
  353. aStream.Read(V[0], LMTS.header.vtxSize);
  354. aStream.Read(V[1], LMTS.header.vtxSize);
  355. aStream.Read(V[2], LMTS.header.vtxSize);
  356. MO.Vertices.add(-V[0].x, V[0].y, V[0].z);
  357. MO.TexCoords.add(V[0].u1, -V[0].v1);
  358. MO.LightmapTexCoords.add(V[0].u2, 1 - V[0].v2);
  359. MO.Vertices.add(-V[2].x, V[2].y, V[2].z);
  360. MO.TexCoords.add(V[2].u1, -V[2].v1);
  361. MO.LightmapTexCoords.add(V[2].u2, 1 - V[2].v2);
  362. MO.Vertices.add(-V[1].x, V[1].y, V[1].z);
  363. MO.TexCoords.add(V[1].u1, -V[1].v1);
  364. MO.LightmapTexCoords.add(V[1].u2, 1 - V[1].v2);
  365. end;
  366. MO.BuildNormals(vi, momtriangles);
  367. vi.free;
  368. matnames.free;
  369. lmnames.free;
  370. setlength(Matinfo, 0);
  371. except
  372. matnames.free;
  373. lmnames.free;
  374. MO.free;
  375. end;
  376. end;
  377. procedure TGLLMTSVectorFile.SaveToStream(aStream: TStream);
  378. var
  379. MO: TMeshObject;
  380. FG: TFGVertexIndexList;
  381. i, j, k, l, lmstartindex, C, matindex: integer;
  382. h: TLMTS_Header;
  383. V: array [0 .. 2] of TLMTS_Vertex;
  384. texData: array of TLMTS_TexData;
  385. subsets: array of TLMTS_Subset;
  386. tris: array of TLMTS_Vertex;
  387. _4cc: cardinal;
  388. matname: AnsiString;
  389. ss: integer;
  390. Matinfo: array of TMaterialInfo;
  391. MatInfoCount: integer;
  392. libmat: TGLLibmaterial;
  393. begin
  394. setlength(tris, 0);
  395. setlength(subsets, 0);
  396. setlength(texData, 0);
  397. C := 0;
  398. lmstartindex := maxint;
  399. for i := 0 to owner.MeshObjects.Count - 1 do
  400. begin
  401. MO := owner.MeshObjects[i];
  402. for j := 0 to MO.FaceGroups.Count - 1 do
  403. begin
  404. FG := TFGVertexIndexList(MO.FaceGroups[j]);
  405. matname := AnsiString(FG.MaterialName);
  406. // no duplicate textures please
  407. matindex := -1;
  408. for k := 0 to high(texData) do
  409. if texData[k].fName = matname then
  410. begin
  411. matindex := k;
  412. break;
  413. end;
  414. if matindex = -1 then // not a duplicate, so add it
  415. begin
  416. SetLength(texData, length(texData) + 1);
  417. with texData[high(texData)] do
  418. begin
  419. matindex := high(texData);
  420. StrPCopy(@fName, matname);
  421. Flags := 0;
  422. end;
  423. inc(C); // used to offest the lightmap index
  424. end;
  425. // set some of the facegroup (subsets) info here.
  426. setlength(subsets, length(subsets) + 1);
  427. with subsets[high(subsets)] do
  428. begin
  429. if (matname <> '') then
  430. TextID1 := matindex
  431. else
  432. TextID1 := $FFFF;
  433. end;
  434. if (FG.lightmapindex > -1) and (lmstartindex > FG.lightmapindex) then
  435. lmstartindex := FG.lightmapindex; // used to offest the lightmap index
  436. end;
  437. end;
  438. if lmstartindex = maxint then
  439. lmstartindex := 0; // cool, lightmaps start from the first index
  440. ss := 0;
  441. for i := 0 to owner.MeshObjects.Count - 1 do
  442. begin
  443. MO := owner.MeshObjects[i];
  444. for j := 0 to MO.FaceGroups.Count - 1 do
  445. begin
  446. FG := TFGVertexIndexList(MO.FaceGroups[j]);
  447. // subset already created earlier, just finish filling the data.
  448. // we needed the "c" and "lmstartindex" to be able to do this
  449. with subsets[ss] do
  450. begin
  451. Offset := length(tris) div 3;
  452. Count := FG.vertexindices.Count div 3;
  453. if (FG.lightmapindex > -1) and Assigned(owner.LightmapLibrary) then
  454. TextID2 := C + FG.lightmapindex - lmstartindex
  455. else
  456. TextID2 := $FFFF;
  457. end;
  458. // fill the vertex data
  459. k := 0;
  460. while k < FG.vertexindices.Count do
  461. begin
  462. for l := 0 to 2 do
  463. begin
  464. with V[l] do
  465. begin
  466. // vertex
  467. x := -MO.Vertices[FG.vertexindices[k + l]].X;
  468. y := MO.Vertices[FG.vertexindices[k + l]].Y;
  469. z := MO.Vertices[FG.vertexindices[k + l]].Z;
  470. // texcoords
  471. u1 := 0;
  472. v1 := 0;
  473. if FG is TFGVertexNormalTexIndexList then
  474. begin
  475. if MO.TexCoords.Count > TFGVertexNormalTexIndexList(FG)
  476. .texcoordIndices[k + l] then
  477. begin
  478. u1 := MO.TexCoords[TFGVertexNormalTexIndexList(FG)
  479. .texcoordIndices[k + l]].X;
  480. v1 := -MO.TexCoords[TFGVertexNormalTexIndexList(FG)
  481. .texcoordIndices[k + l]].Y;
  482. end;
  483. end
  484. else if FG is TFGIndexTexCoordList then
  485. begin
  486. u1 := TFGIndexTexCoordList(FG).TexCoords[k + l].X;
  487. v1 := -TFGIndexTexCoordList(FG).TexCoords[k + l].Y;
  488. end
  489. else if MO.TexCoords.Count > FG.vertexindices[k + l] then
  490. begin
  491. u1 := MO.TexCoords[FG.vertexindices[k + l]].X;
  492. v1 := -MO.TexCoords[FG.vertexindices[k + l]].Y;
  493. end;
  494. // lightmap texcoords
  495. u2 := 0;
  496. v2 := 0;
  497. if MO.LightmapTexCoords.Count > FG.vertexindices[k + l] then
  498. begin
  499. u2 := MO.LightmapTexCoords[FG.vertexindices[k + l]].X;
  500. v2 := 1 - MO.LightmapTexCoords[FG.vertexindices[k + l]].Y;
  501. end;
  502. end;
  503. end;
  504. setlength(tris, length(tris) + 3);
  505. tris[high(tris) - 2] := V[0];
  506. tris[high(tris) - 1] := V[2];
  507. tris[high(tris)] := V[1];
  508. inc(k, 3);
  509. end;
  510. inc(ss);
  511. end;
  512. end;
  513. setlength(Matinfo, 0);
  514. // store the material properties..
  515. if Assigned(owner.MaterialLibrary) then
  516. begin
  517. for i := 0 to high(texData) do
  518. begin
  519. libmat := owner.MaterialLibrary.Materials.GetLibMaterialByName
  520. (String(texData[i].fName));
  521. if Assigned(libmat) then
  522. begin
  523. setlength(Matinfo, length(Matinfo) + 1);
  524. with Matinfo[high(Matinfo)] do
  525. begin
  526. FShininess := libmat.Material.FrontProperties.Shininess;
  527. BShininess := libmat.Material.BackProperties.Shininess;
  528. FAmbient := libmat.Material.FrontProperties.Ambient.Color;
  529. FDiffuse := libmat.Material.FrontProperties.Diffuse.Color;
  530. FEmission := libmat.Material.FrontProperties.Emission.Color;
  531. FSpecular := libmat.Material.FrontProperties.Specular.Color;
  532. BAmbient := libmat.Material.BackProperties.Ambient.Color;
  533. BDiffuse := libmat.Material.BackProperties.Diffuse.Color;
  534. BEmission := libmat.Material.BackProperties.Emission.Color;
  535. BSpecular := libmat.Material.BackProperties.Specular.Color;
  536. ImageAlpha := libmat.Material.Texture.ImageAlpha;
  537. magFilter := libmat.Material.Texture.magFilter;
  538. minFilter := libmat.Material.Texture.minFilter;
  539. TextureMode := libmat.Material.Texture.TextureMode;
  540. TextureWrap := libmat.Material.Texture.TextureWrap;
  541. Blendingmode := libmat.Material.Blendingmode;
  542. FaceCulling := libmat.Material.FaceCulling;
  543. mathash := libmat.NameHashKey;
  544. end;
  545. end;
  546. end;
  547. end;
  548. // add the lightmap texture names to the texdata list
  549. C := length(texData);
  550. if Assigned(owner.LightmapLibrary) then
  551. for i := 0 to owner.MeshObjects.Count - 1 do
  552. begin
  553. MO := owner.MeshObjects[i];
  554. for j := 0 to MO.FaceGroups.Count - 1 do
  555. begin
  556. FG := TFGVertexIndexList(MO.FaceGroups[j]);
  557. if FG.lightmapindex > -1 then
  558. begin
  559. matname := AnsiString(owner.LightmapLibrary.Materials
  560. [FG.lightmapindex].Name);
  561. // no duplicate textures please
  562. matindex := -1;
  563. for k := C to high(texData) do
  564. if texData[k].fName = matname then
  565. begin
  566. matindex := k;
  567. break;
  568. end;
  569. if matindex = -1 then // not a duplicate, so add it
  570. begin
  571. SetLength(texData, length(texData) + 1);
  572. with texData[high(texData)] do
  573. begin
  574. StrPCopy(pansichar(@fName), matname);
  575. Flags := 1;
  576. end;
  577. end;
  578. end;
  579. end;
  580. end;
  581. // fill and write the file header
  582. with h do
  583. begin
  584. ID := C_LMTS_ID;
  585. Ver := C_LMTS_VER;
  586. headerSize := 24 + 8 + (length(Matinfo) * SizeOf(TMaterialInfo));
  587. nTexts := length(texData);
  588. nSubsets := length(subsets);
  589. nTris := length(tris) div 3;
  590. subSize := SizeOf(TLMTS_Subset);
  591. vtxSize := SizeOf(TLMTS_Vertex);
  592. end;
  593. aStream.Write(h, SizeOf(h));
  594. aStream.Write('MATI', 4);
  595. MatInfoCount := length(Matinfo);
  596. aStream.Write(MatInfoCount, SizeOf(MatInfoCount));
  597. // write the materials info
  598. for i := 0 to high(Matinfo) do
  599. aStream.Write(Matinfo[i], SizeOf(Matinfo[i]));
  600. // write the texture names
  601. _4cc := C_LMTS_TEXT;
  602. aStream.Write(_4cc, SizeOf(_4cc));
  603. for i := 0 to high(texData) do
  604. aStream.Write(texData[i], SizeOf(texData[i]));
  605. // fagegroups
  606. _4cc := C_LMTS_SUBS;
  607. aStream.Write(_4cc, SizeOf(_4cc));
  608. for i := 0 to high(subsets) do
  609. aStream.Write(subsets[i], SizeOf(subsets[i]));
  610. // vertex data
  611. _4cc := C_LMTS_TRIS;
  612. aStream.Write(_4cc, SizeOf(_4cc));
  613. for i := 0 to high(tris) do
  614. aStream.Write(tris[i], SizeOf(tris[i]));
  615. // free up used memory
  616. setlength(tris, 0);
  617. setlength(subsets, 0);
  618. setlength(texData, 0);
  619. setlength(Matinfo, 0);
  620. end;
  621. //-----------------------------------------------
  622. initialization
  623. //-----------------------------------------------
  624. RegisterVectorFileFormat('lmts', 'Pulsar Studio LMTS File Format',
  625. TGLLMTSVectorFile);
  626. end.