GXS.FileLWO.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.FileLWO;
  5. (* Support-code to load Lightwave LWO Files (v6.0+, partial support) *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. System.SysUtils,
  10. System.Classes,
  11. System.Math,
  12. Stage.VectorTypes,
  13. Stage.VectorGeometry,
  14. GXS.VectorLists,
  15. GXS.Texture,
  16. GXS.Material,
  17. GXS.VectorFileObjects,
  18. Formatx.LWO;
  19. type
  20. TgxLWOVectorFile = class(TgxVectorFile)
  21. private
  22. FLWO: TLWObjectFile;
  23. FPnts: TLWPnts;
  24. procedure AddLayr(Layr: TLWLayr; LWO: TLWObjectFile);
  25. procedure AddSurf(Surf: TLWSurf; LWO: TLWObjectFile);
  26. procedure AddPnts(Pnts: TLWPnts; Mesh: TgxMeshObject);
  27. procedure AddPols(Pols: TLWPols; Mesh: TgxMeshObject);
  28. procedure AddVMap(VMap: TLWVMap; Mesh: TgxMeshObject);
  29. public
  30. procedure LoadFromStream(aStream: TStream); override;
  31. end;
  32. //=============================================================================
  33. implementation
  34. //=============================================================================
  35. type
  36. PVector3f = ^TVector3f;
  37. function CalcTriNorm(v1, v2, v3: TVec12): TVector3f;
  38. var
  39. e1, e2: TVector3f;
  40. begin
  41. e1 := VectorSubtract(PVector3f(@v2)^, PVector3f(@v1)^);
  42. e2 := VectorSubtract(PVector3f(@v3)^, PVector3f(@v1)^);
  43. VectorCrossProduct(e1, e2, result);
  44. result := VectorNormalize(result);
  45. end;
  46. type
  47. TNormBuffer = record
  48. count, lasttag: TU2;
  49. end;
  50. TNormBufferDynArray = array of TNormBuffer;
  51. (******************************* TgxLWOVectorFile *****************************)
  52. procedure TgxLWOVectorFile.AddLayr(Layr: TLWLayr; LWO: TLWObjectFile);
  53. var
  54. Idx: Integer;
  55. Mesh: TgxMeshObject;
  56. Pnts: TLWPnts;
  57. begin
  58. // Add mesh
  59. Mesh := TgxMeshObject.CreateOwned(Owner.MeshObjects);
  60. with Mesh do
  61. begin
  62. Name := Layr.Name;
  63. Mode := momFaceGroups;
  64. // pnts
  65. Idx := Layr.Items.FindChunk(@FindChunkById, @ID_PNTS);
  66. Pnts := TLWPnts(Layr.Items[Idx]);
  67. if Idx <> -1 then
  68. AddPnts(Pnts, Mesh);
  69. // vertex maps
  70. Idx := TLWPnts(Layr.Items[Idx]).Items.FindChunk(@FindChunkById, @ID_VMAP);
  71. while Idx <> -1 do
  72. begin
  73. AddVMap(TLWVMap(Pnts.Items[Idx]), Mesh);
  74. Idx := Pnts.Items.FindChunk(@FindChunkById, @ID_VMAP, Idx + 1);
  75. end;
  76. // Polygons
  77. Idx := Layr.Items.FindChunk(@FindChunkById, @ID_POLS);
  78. while Idx <> -1 do
  79. begin
  80. AddPols(TLWPols(Layr.Items[Idx]), Mesh);
  81. Idx := Layr.Items.FindChunk(@FindChunkById, @ID_POLS, Idx + 1);
  82. end;
  83. // Normals.Normalize;
  84. end;
  85. FPnts := nil;
  86. end;
  87. procedure TgxLWOVectorFile.AddPnts(Pnts: TLWPnts; Mesh: TgxMeshObject);
  88. var
  89. i: Integer;
  90. begin
  91. FPnts := Pnts;
  92. with Mesh do
  93. begin
  94. Vertices.Capacity := Pnts.PntsCount;
  95. TexCoords.Capacity := Pnts.PntsCount;
  96. TexCoords.AddNulls(Pnts.PntsCount);
  97. for i := 0 to Pnts.PntsCount - 1 do
  98. Vertices.Add(PAffineVector(@Pnts.Pnts[i])^);
  99. end;
  100. end;
  101. procedure TgxLWOVectorFile.AddPols(Pols: TLWPols; Mesh: TgxMeshObject);
  102. var
  103. Idx: Integer;
  104. i, j, k, PolyIdx, NormIdx: Integer;
  105. TagPolys: TU2DynArray;
  106. FaceGrp: TFGVertexNormalTexIndexList;
  107. VertPolys: TU2DynArray;
  108. begin
  109. SetLength(VertPolys, 0);
  110. with Pols do
  111. begin
  112. // face type pols chunk
  113. if PolsType = POLS_TYPE_FACE then
  114. begin
  115. Idx := Items.FindChunk(@FindChunkById, @ID_PTAG);
  116. while Idx <> -1 do
  117. begin
  118. with TLWPTag(Items[Idx]) do
  119. begin
  120. if MapType = PTAG_TYPE_SURF then
  121. begin
  122. // for each tag
  123. for i := 0 to TagCount - 1 do
  124. begin
  125. // get polygons using this tag
  126. if GetPolsByTag(Tags[i], TagPolys) > 0 then
  127. begin
  128. // make the facegroup and set the material name
  129. FaceGrp := TFGVertexNormalTexIndexList.CreateOwned(Mesh.FaceGroups);
  130. FaceGrp.MaterialName := FLWO.SurfaceByTag[Tags[i]].Name;
  131. FaceGrp.Mode := fgmmTriangles;
  132. // for each polygon in the current surface Tags[i]
  133. for j := 0 to Length(TagPolys) - 1 do
  134. begin
  135. PolyIdx := PolsByIndex[TagPolys[j]];
  136. // triple 2,3 and 4 point ngons
  137. case Indices[PolyIdx] of
  138. 2:
  139. begin
  140. // triangle line segment
  141. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
  142. FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
  143. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[1])^);
  144. FaceGrp.Add(Indices[PolyIdx + 2], NormIdx, Indices[PolyIdx + 1]);
  145. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
  146. FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
  147. end;
  148. 3: for k := 1 to 3 do
  149. begin
  150. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[k - 1])^);
  151. FaceGrp.Add(Indices[PolyIdx + k], NormIdx, Indices[PolyIdx + 1]);
  152. end;
  153. 4:
  154. begin
  155. // triangle A
  156. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
  157. FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
  158. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[1])^);
  159. FaceGrp.Add(Indices[PolyIdx + 2], NormIdx, Indices[PolyIdx + 1]);
  160. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[2])^);
  161. FaceGrp.Add(Indices[PolyIdx + 3], NormIdx, Indices[PolyIdx + 1]);
  162. // triangle B
  163. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[0])^);
  164. FaceGrp.Add(Indices[PolyIdx + 1], NormIdx, Indices[PolyIdx + 1]);
  165. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[2])^);
  166. FaceGrp.Add(Indices[PolyIdx + 3], NormIdx, Indices[PolyIdx + 1]);
  167. NormIdx := Mesh.Normals.Add(PVector3f(@PolsInfo[TagPolys[j]].vnorms[3])^);
  168. FaceGrp.Add(Indices[PolyIdx + 4], NormIdx, Indices[PolyIdx + 1]);
  169. end;
  170. end;
  171. end;
  172. SetLength(TagPolys, 0);
  173. end;
  174. end;
  175. end
  176. else
  177. if MapType = PTAG_TYPE_PART then
  178. begin
  179. // Todo: PTag PART
  180. end
  181. else
  182. if MapType = PTAG_TYPE_SMGP then
  183. begin
  184. // Todo: PTag Smooth Group
  185. end;
  186. Idx := Items.FindChunk(@FindChunkById, @ID_PTAG, Idx + 1);
  187. end;
  188. end;
  189. end
  190. else
  191. //// curv type pols chunk (catmull-rom splines)
  192. if PolsType = POLS_TYPE_CURV then
  193. begin
  194. // Todo: CURV Pols import
  195. end
  196. else
  197. {// nurbs patch pols type chunk}
  198. if PolsType = POLS_TYPE_PTCH then
  199. begin
  200. {Todo: NURBS Patch Pols import}
  201. end
  202. else
  203. {// metaball pols type chunk}
  204. if PolsType = POLS_TYPE_MBAL then
  205. begin
  206. {Todo: MetaBall type Pols import}
  207. end
  208. else
  209. {// bone pols type chunk}
  210. if PolsType = POLS_TYPE_BONE then
  211. begin
  212. {Todo: Bone Pols import}
  213. end;
  214. SetLength(TagPolys, 0);
  215. end;
  216. end;
  217. procedure TgxLWOVectorFile.AddSurf(Surf: TLWSurf; LWO: TLWObjectFile);
  218. var
  219. matLib: TgxMaterialLibrary;
  220. libMat: TgxLibMaterial;
  221. tex2Mat: TgxLibMaterial;
  222. colr: TColr12;
  223. FloatParm, tran, refl: TF4;
  224. WordParm: TU2;
  225. StrParm: string;
  226. Idx: integer;
  227. begin
  228. // DONE: implement surface inheritance
  229. if GetOwner is TgxBaseMesh then
  230. begin
  231. matLib := TgxBaseMesh(GetOwner).MaterialLibrary;
  232. if Assigned(matLib) then
  233. begin
  234. libMat := matLib.Materials.GetLibMaterialByName(Surf.Name);
  235. if not Assigned(libMat) then
  236. begin
  237. libMat := matLib.Materials.Add;
  238. libMat.Name := Surf.Name;
  239. with libMat.Material.FrontProperties do
  240. begin
  241. tran := Surf.FloatParam[ID_TRAN];
  242. if tran <> 0 then
  243. libMat.Material.BlendingMode := bmTransparency;
  244. colr := Surf.Vec3Param[ID_COLR];
  245. // Ambient.Color := VectorMake(colr[0],colr[1],colr[2],1);
  246. Ambient.Color := VectorMake(0, 0, 0, 1);
  247. (* Diffuse *)
  248. FloatParm := Surf.FloatParam[ID_DIFF];
  249. Diffuse.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, tran);
  250. (* Luminosity -> Emission *)
  251. FloatParm := Surf.FloatParam[ID_LUMI];
  252. Emission.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, 1);
  253. (* Specularity *)
  254. FloatParm := Surf.FloatParam[ID_SPEC];
  255. Specular.Color := VectorMake(colr[0] * FloatParm, colr[1] * FloatParm, colr[2] * FloatParm, 1);
  256. (* Glossiness -> Shininess *)
  257. FloatParm := Surf.FloatParam[ID_GLOS];
  258. Shininess := Round(Power(2, 7 * FloatParm));
  259. (* Polygon sidedness *)
  260. WordParm := Surf.WordParam[ID_SIDE];
  261. if (WordParm and SIDE_BACK) = SIDE_BACK then
  262. AssignTo(libMat.Material.BackProperties);
  263. (* Reflection settings *)
  264. refl := Surf.FloatParam[ID_REFL];
  265. if refl > 0 then
  266. begin
  267. // Check the reflection options
  268. WordParm := Surf.WordParam[ID_RFOP];
  269. if WordParm > RFOP_RAYTRACEANDBACKDROP then
  270. begin
  271. WordParm := Surf.VXParam[ID_RIMG];
  272. Idx := Surf.RootChunks.FindChunk(@FindClipByClipIndex, @WordParm);
  273. if Idx <> -1 then
  274. begin
  275. StrParm := string(PAnsiChar(TLWClip(Surf.RootChunks[Idx]).ParamAddr[ID_STIL]));
  276. StrParm := GetContentDir.FindContent(ToDosPath(StrParm));
  277. if FileExists(StrParm) then
  278. try
  279. if (not libMat.Material.Texture.Enabled) then
  280. tex2Mat := libMat
  281. else
  282. tex2Mat := matLib.Materials.Add;
  283. with tex2Mat do
  284. begin
  285. Material.Texture.Image.LoadFromFile(StrParm);
  286. Material.Texture.Disabled := False;
  287. with Material.Texture do
  288. begin
  289. MappingMode := tmmCubeMapReflection;
  290. if refl < 100 then
  291. TextureMode := tmBlend
  292. else
  293. TextureMode := tmDecal;
  294. end;
  295. end;
  296. libMat.Texture2Name := 'REFL_' + ExtractFileName(StrParm);
  297. except
  298. on E: ETexture do
  299. begin
  300. if not Self.Owner.IgnoreMissingTextures then
  301. raise;
  302. end;
  303. end;
  304. end;
  305. end;
  306. end;
  307. end;
  308. end;
  309. end;
  310. end;
  311. end;
  312. procedure TgxLWOVectorFile.AddVMap(VMap: TLWVMap; Mesh: TgxMeshObject);
  313. var
  314. i: integer;
  315. begin
  316. with VMap, Mesh do
  317. begin
  318. // texture coords
  319. if VMapType = VMAP_TYPE_TXUV then
  320. begin
  321. for i := 0 to ValueCount - 1 do
  322. TexCoords.Items[Value[i].vert] := AffineVectorMake(Value[i].values[0], Value[i].values[1], 0);
  323. end
  324. else
  325. {// vertex weight map}
  326. if VMapType = VMAP_TYPE_WGHT then
  327. begin
  328. // Todo: WeightMap import
  329. end
  330. else
  331. {// vertex morph (relative)}
  332. if VMapType = VMAP_TYPE_MORF then
  333. begin
  334. // Todo: Morph target (relative) import
  335. end
  336. else
  337. {// vertex morph (absolute)}
  338. if VMapType = VMAP_TYPE_SPOT then
  339. begin
  340. // Todo: Morph target (absolute) import
  341. end;
  342. end;
  343. end;
  344. procedure TgxLWOVectorFile.LoadFromStream(aStream: TStream);
  345. var
  346. Ind: Integer;
  347. begin
  348. FLWO := TLWObjectFile.Create;
  349. with FLWO do
  350. try
  351. LoadFromStream(aStream);
  352. // Add Surfaces to material list
  353. Ind := Chunks.FindChunk(@FindChunkById, @ID_SURF, 0);
  354. while Ind <> -1 do
  355. begin
  356. AddSurf(TLWSurf(Chunks[Ind]), FLWO);
  357. Ind := Chunks.FindChunk(@FindChunkById, @ID_SURF, Ind + 1);
  358. end;
  359. // Lw layer
  360. Ind := Chunks.FindChunk(@FindChunkById, @ID_LAYR, 0);
  361. while Ind <> -1 do
  362. begin
  363. AddLayr(TLWLayr(Chunks[Ind]), FLWO);
  364. Ind := Chunks.FindChunk(@FindChunkById, @ID_LAYR, Ind + 1);
  365. end;
  366. finally
  367. FreeAndNil(FLWO);
  368. end;
  369. end;
  370. //---------------------------------------------------
  371. initialization
  372. //---------------------------------------------------
  373. RegisterVectorFileFormat('lwo', 'Lightwave3D object file (6.0 or above)', TgxLWOVectorFile);
  374. finalization
  375. end.