GXS.FileLMTS.pas 20 KB

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