GLFileB3D.pas 11 KB

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