GLS.FileB3D.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.FileB3D;
  5. (* B3D VectorFile class to load Blitz 3D model files *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. GLS.VectorFileObjects,
  11. GLS.ApplicationFileIO,
  12. GLS.Texture,
  13. GLS.TextureFormat,
  14. GLS.Material,
  15. GLS.VectorTypes,
  16. GLS.VectorGeometry,
  17. GLS.VectorLists,
  18. Formats.B3D;
  19. type
  20. TGLB3DVectorFile = class(TGLVectorFile)
  21. public
  22. class function Capabilities: TGLDataFileCapabilities; override;
  23. procedure LoadFromStream(AStream: TStream); override;
  24. end;
  25. // ------------------------------------------------------------------
  26. implementation
  27. // ------------------------------------------------------------------
  28. // ------------------------------ TGLB3DVectorFile ------------------------------
  29. class function TGLB3DVectorFile.Capabilities: TGLDataFileCapabilities;
  30. begin
  31. Result := [DfcRead];
  32. end;
  33. procedure TGLB3DVectorFile.LoadFromStream(AStream: TStream);
  34. var
  35. B3d: TFileB3D;
  36. S: string;
  37. Mo: TGLMeshObject;
  38. I, J: Integer;
  39. FaceGroup: TFGVertexIndexList;
  40. // lightmapBmp : TBitmap;
  41. Node: PNODEChunk;
  42. B3DMat: TB3DMaterial;
  43. B3DTex: TB3DTexture;
  44. B3DLightTex: TB3DTexture;
  45. Vertex: PVertexData;
  46. Triangles: PTRISChunk;
  47. V, V1: TAffineVector;
  48. Matrix: TGLMatrix;
  49. MatLib: TGLMaterialLibrary;
  50. LightLib: TGLMaterialLibrary;
  51. RotQuat: TQuaternion;
  52. RotMat: TGLMatrix;
  53. function GetOrAllocateMaterial(MaterialNum: Integer; AMat: TB3DMaterial;
  54. ATex: TB3DTexture; ALightmap: TB3DTexture): string;
  55. var
  56. LibMat: TGLLibMaterial;
  57. TexName: string;
  58. LightName: string;
  59. begin
  60. if GetOwner is TGLBaseMesh then
  61. begin
  62. MatLib := TGLBaseMesh(GetOwner).MaterialLibrary;
  63. LightLib := TGLBaseMesh(GetOwner).LightmapLibrary;
  64. // got a linked material library?
  65. if Assigned(MatLib) then
  66. begin
  67. Result := AMat.GetMaterialName;
  68. // add base material
  69. LibMat := MatLib.Materials.GetLibMaterialByName(Result);
  70. if not Assigned(LibMat) then
  71. begin
  72. if Assigned(ATex) then
  73. TexName := ATex.GetTextureName
  74. else
  75. TexName := '';
  76. if not FileExists(TexName) then
  77. TexName := ExtractFileName(TexName);
  78. if TexName <> '' then
  79. LibMat := MatLib.AddTextureMaterial(Result + IntToStr(MaterialNum),
  80. TexName, False)
  81. else
  82. begin
  83. LibMat := MatLib.Materials.Add;
  84. LibMat.Name := Result + IntToStr(MaterialNum);
  85. end;
  86. Libmat.Material.FrontProperties.Diffuse.Red := AMat.MaterialData.Red;
  87. Libmat.Material.FrontProperties.Diffuse.Green :=
  88. AMat.MaterialData.Green;
  89. Libmat.Material.FrontProperties.Diffuse.Blue :=
  90. AMat.MaterialData.Blue;
  91. Libmat.Material.FrontProperties.Diffuse.Alpha :=
  92. AMat.MaterialData.Alpha;
  93. Libmat.Material.FrontProperties.Shininess :=
  94. Round(AMat.MaterialData.Shininess * 100.0);
  95. Libmat.Material.MaterialOptions := [MoNoLighting];
  96. if AMat.MaterialData.Alpha <> 1 then
  97. begin
  98. Libmat.Material.FaceCulling := FcNoCull;
  99. Libmat.Material.BlendingMode := BmTransparency;
  100. end;
  101. if Assigned(ATex) then
  102. begin
  103. LibMat.TextureOffset.AsAffineVector :=
  104. AffineVectorMake(ATex.TextureData.X_pos,
  105. ATex.TextureData.Y_pos, 0);
  106. LibMat.TextureScale.AsAffineVector :=
  107. AffineVectorMake(ATex.TextureData.X_scale,
  108. ATex.TextureData.Y_scale, 1);
  109. if ATex.TextureData.Flags = 2 then
  110. begin
  111. Libmat.Material.FaceCulling := FcNoCull;
  112. Libmat.Material.BlendingMode := BmTransparency;
  113. end;
  114. if AMat.MaterialData.Alpha <> 1 then
  115. begin
  116. Libmat.Material.Texture.ImageAlpha := TiaAlphaFromIntensity;
  117. Libmat.Material.Texture.TextureFormat := TfRGBA;
  118. Libmat.Material.Texture.TextureMode := TmModulate;
  119. end;
  120. end;
  121. end;
  122. // add lightmap material
  123. if (Assigned(LightLib)) and (Assigned(ALightmap)) then
  124. begin
  125. LightName := ALightmap.GetTextureName;
  126. // add base material
  127. LibMat := LightLib.Materials.GetLibMaterialByName(LightName
  128. { + IntToStr(MaterialNum) } );
  129. if not Assigned(LibMat) then
  130. begin
  131. if not FileExists(LightName) then
  132. LightName := ExtractFileName(LightName);
  133. LibMat := LightLib.AddTextureMaterial(LightName
  134. { + IntToStr(MaterialNum) } , LightName, False);
  135. LibMat.Material.Texture.TextureMode := TmReplace;
  136. if Assigned(ALightMap) then
  137. begin
  138. LibMat.TextureOffset.AsAffineVector :=
  139. AffineVectorMake(ALightMap.TextureData.X_pos,
  140. ALightMap.TextureData.Y_pos, 0);
  141. LibMat.TextureScale.AsAffineVector :=
  142. AffineVectorMake(ALightMap.TextureData.X_scale,
  143. ALightMap.TextureData.Y_scale, 1);
  144. end;
  145. end;
  146. // modify the material lightmap index
  147. AMat.MaterialData.Texture_id[1] := LibMat.Index;
  148. end;
  149. end
  150. else
  151. Result := '';
  152. end
  153. else
  154. Result := '';
  155. end;
  156. begin
  157. B3d := TFileB3D.Create;
  158. try
  159. // first, load the b3d model sturctures from stream
  160. B3d.LoadFromStream(AStream);
  161. // then add all the materials and lightmaps from b3d structures
  162. for I := 0 to B3d.Materials.Count - 1 do
  163. begin
  164. B3DMat := TB3DMaterial(B3d.Materials.Objects[I]);
  165. B3DTex := nil;
  166. B3DLightTex := nil;
  167. // check if there is one texture layer
  168. if B3DMat.MaterialData.N_texs > 0 then
  169. begin
  170. if B3DMat.MaterialData.Texture_id[0] >= 0 then
  171. B3DTex := TB3DTexture(B3d.Textures.Objects
  172. [B3DMat.MaterialData.Texture_id[0]]);
  173. // check if there are two texture layer
  174. if B3DMat.MaterialData.N_texs > 1 then
  175. // why lightmap in some case on channel 2?
  176. if B3DMat.MaterialData.Texture_id[1] >= 0 then
  177. B3DLightTex :=
  178. TB3DTexture(B3d.Textures.Objects
  179. [B3DMat.MaterialData.Texture_id[1]])
  180. else
  181. { //check if there are three texture layer }
  182. if B3DMat.MaterialData.N_texs > 2 then
  183. if B3DMat.MaterialData.Texture_id[2] >= 0 then
  184. B3DLightTex :=
  185. TB3DTexture(B3d.Textures.Objects
  186. [B3DMat.MaterialData.Texture_id[2]]);
  187. end;
  188. GetOrAllocateMaterial(I, B3DMat, B3DTex, B3DLightTex);
  189. end;
  190. if GetOwner is TGLBaseMesh then
  191. (GetOwner as TGLBaseMesh).NormalsOrientation := MnoDefault;
  192. Node := B3d.Nodes.NodeData;
  193. while Node <> nil do
  194. begin
  195. if Node^.Meshes <> nil then
  196. begin
  197. Mo := TGLMeshObject.CreateOwned(Owner.MeshObjects);
  198. SetString(S, Node^.Name, Strlen(Node^.Name));
  199. // if Pos('16', s)>1 then
  200. // Pos('17', s);
  201. Mo.Name := S;
  202. Mo.Mode := MomFaceGroups;
  203. // add all the vertices, normals, colors and texture-coords(including the lightmap texture)
  204. Vertex := Node^.Meshes^.Vertices.Vertices;
  205. while Assigned(Vertex) do
  206. begin
  207. // W3D modif inversed z
  208. Mo.Vertices.Add(AffineVectorMake(Vertex^.Y, Vertex^.X, Vertex^.Z));
  209. if (Node^.Meshes^.Vertices.Flags and 1) > 0 then
  210. Mo.Normals.Add(VectorNormalize(AffineVectorMake(Vertex^.Ny,
  211. Vertex^.Nx, Vertex^.Nz)));
  212. if (Node^.Meshes^.Vertices.Flags and 2) > 0 then
  213. begin
  214. Mo.Colors.Add(VectorMake(Vertex^.Red, Vertex^.Green, Vertex^.Blue,
  215. Vertex^.Alpha));
  216. end;
  217. case Node^.Meshes^.Vertices.Tex_coord_sets of
  218. 1:
  219. begin
  220. case Node^.Meshes^.Vertices.Tex_coord_set_size of
  221. 2:
  222. Mo.TexCoords.Add(Vertex^.Tex_coords[0],
  223. -Vertex^.Tex_coords[1], 0);
  224. 3:
  225. Mo.TexCoords.Add(Vertex^.Tex_coords[0],
  226. -Vertex^.Tex_coords[1], Vertex^.Tex_coords[2]);
  227. end;
  228. end;
  229. 2: // lightmap tex_coord included
  230. begin
  231. case Node^.Meshes^.Vertices.Tex_coord_set_size of
  232. 2:
  233. Mo.TexCoords.Add(Vertex^.Tex_coords[0],
  234. -Vertex^.Tex_coords[1], 0);
  235. 3:
  236. Mo.TexCoords.Add(Vertex^.Tex_coords[0],
  237. -Vertex^.Tex_coords[1], Vertex^.Tex_coords[2]);
  238. end;
  239. Mo.LightMapTexCoords.Add
  240. (Vertex^.Tex_coords
  241. [Node^.Meshes^.Vertices.Tex_coord_set_size],
  242. -Vertex^.Tex_coords
  243. [Node^.Meshes^.Vertices.Tex_coord_set_size + 1]);
  244. end;
  245. end;
  246. Vertex := Vertex^.Next;
  247. end;
  248. // add facegroups
  249. Triangles := Node^.Meshes^.Triangles;
  250. while Assigned(Triangles) do
  251. begin
  252. FaceGroup := TFGVertexIndexList.CreateOwned(Mo.FaceGroups);
  253. if Triangles^.Brush_id >= 0 then
  254. begin
  255. FaceGroup.MaterialName := B3d.Materials[Triangles^.Brush_id] +
  256. InttoStr(Triangles^.Brush_id);
  257. FaceGroup.LightMapIndex :=
  258. TB3DMaterial(B3d.Materials.Objects[Triangles^.Brush_id])
  259. .MaterialData.Texture_id[1];
  260. end
  261. else
  262. begin
  263. FaceGroup.MaterialName := '';
  264. FaceGroup.LightMapIndex := -1;
  265. end;
  266. for J := 0 to Length(Triangles^.Vertex_id) - 1 do
  267. FaceGroup.VertexIndices.Add(Triangles^.Vertex_id[J]);
  268. while FaceGroup.VertexIndices.Count mod 3 <> 0 do
  269. FaceGroup.VertexIndices.Delete(FaceGroup.VertexIndices.Count - 1);
  270. Triangles := Triangles.Next;
  271. FaceGroup.Reverse;
  272. end;
  273. RotQuat := QuaternionMake([Node^.Rotation.Z, Node^.Rotation.Y,
  274. Node^.Rotation.W], Node^.Rotation.X);
  275. RotMat := QuaternionToMatrix(RotQuat);
  276. Mo.Vertices.TransformAsVectors(RotMat);
  277. (*
  278. mo.SetPosition( Node^.Position[1], Node^.Position[0], Node^.Position[2]);
  279. mo.SetScale( Node^.Scale[1], Node^.Scale[0], Node^.Scale[2]);
  280. *)
  281. if Pos('ENT_', UpperCase(Mo.Name)) = 0 then
  282. V := AffineVectorMake(Node^.Position.Y,
  283. Node^.Position.X, Node^.Position.Z)
  284. else
  285. begin
  286. V := AffineVectorMake(0.0, 0.0, 0.0);
  287. end;
  288. V1 := AffineVectorMake(Node^.Scale.Y, Node^.Scale.X, Node^.Scale.Z);
  289. Matrix := CreateScaleAndTranslationMatrix(VectorMake(V1), VectorMake(V));
  290. Mo.Vertices.TransformAsPoints(Matrix);
  291. end;
  292. Node := Node^.Next;
  293. end;
  294. finally
  295. B3d.Free;
  296. end;
  297. end;
  298. // ------------------------------------------------------------------
  299. initialization
  300. // ------------------------------------------------------------------
  301. RegisterVectorFileFormat('b3d', 'Blitz 3D model files', TGLB3DVectorFile);
  302. end.