123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- //
- // The graphics engine GXScene https://github.com/glscene
- //
- unit GXS.FileB3D;
- (* B3D VectorFile class to load Blitz 3D model files *)
- interface
- uses
- System.Classes,
- System.SysUtils,
- Stage.VectorTypes,
- Stage.VectorGeometry,
- Stage.TextureFormat,
- GXS.ApplicationFileIO,
- GXS.VectorLists,
- GXS.VectorFileObjects,
- GXS.Texture,
- GXS.Material,
- Formatx.B3D;
- type
- TgxB3DVectorFile = class(TgxVectorFile)
- public
- class function Capabilities: TDataFileCapabilities; override;
- procedure LoadFromStream(AStream: TStream); override;
- end;
- implementation // -------------------------------------------------------------
- // ------------------------------ TgxB3DVectorFile ----------------------------
- class function TgxB3DVectorFile.Capabilities: TDataFileCapabilities;
- begin
- Result := [DfcRead];
- end;
- procedure TgxB3DVectorFile.LoadFromStream(AStream: TStream);
- var
- B3d: TFileB3D;
- S: string;
- Mo: TgxMeshObject;
- I, J: Integer;
- FaceGroup: TgxFGVertexIndexList;
- // lightmapBmp : TBitmap;
- Node: PNODEChunk;
- B3DMat: TB3DMaterial;
- B3DTex: TB3DTexture;
- B3DLightTex: TB3DTexture;
- Vertex: PVertexData;
- Triangles: PTRISChunk;
- V, V1: TAffineVector;
- Matrix: TMatrix4f;
- MatLib: TgxMaterialLibrary;
- LightLib: TgxMaterialLibrary;
- RotQuat: TQuaternion;
- RotMat: TMatrix4f;
- function GetOrAllocateMaterial(MaterialNum: Integer; AMat: TB3DMaterial;
- ATex: TB3DTexture; ALightmap: TB3DTexture): string;
- var
- LibMat: TgxLibMaterial;
- TexName: string;
- LightName: string;
- begin
- if GetOwner is TgxBaseMesh then
- begin
- MatLib := TgxBaseMesh(GetOwner).MaterialLibrary;
- LightLib := TgxBaseMesh(GetOwner).LightmapLibrary;
- // got a linked material library?
- if Assigned(MatLib) then
- begin
- Result := AMat.GetMaterialName;
- // add base material
- LibMat := MatLib.Materials.GetLibMaterialByName(Result);
- if not Assigned(LibMat) then
- begin
- if Assigned(ATex) then
- TexName := ATex.GetTextureName
- else
- TexName := '';
- if not FileExists(TexName) then
- TexName := ExtractFileName(TexName);
- if TexName <> '' then
- LibMat := MatLib.AddTextureMaterial(Result + IntToStr(MaterialNum),
- TexName, False)
- else
- begin
- LibMat := MatLib.Materials.Add;
- LibMat.Name := Result + IntToStr(MaterialNum);
- end;
- Libmat.Material.FrontProperties.Diffuse.Red := AMat.MaterialData.Red;
- Libmat.Material.FrontProperties.Diffuse.Green :=
- AMat.MaterialData.Green;
- Libmat.Material.FrontProperties.Diffuse.Blue :=
- AMat.MaterialData.Blue;
- Libmat.Material.FrontProperties.Diffuse.Alpha :=
- AMat.MaterialData.Alpha;
- Libmat.Material.FrontProperties.Shininess :=
- Round(AMat.MaterialData.Shininess * 100.0);
- Libmat.Material.MaterialOptions := [MoNoLighting];
- if AMat.MaterialData.Alpha <> 1 then
- begin
- Libmat.Material.FaceCulling := FcNoCull;
- Libmat.Material.BlendingMode := BmTransparency;
- end;
- if Assigned(ATex) then
- begin
- LibMat.TextureOffset.AsAffineVector :=
- AffineVectorMake(ATex.TextureData.X_pos,
- ATex.TextureData.Y_pos, 0);
- LibMat.TextureScale.AsAffineVector :=
- AffineVectorMake(ATex.TextureData.X_scale,
- ATex.TextureData.Y_scale, 1);
- if ATex.TextureData.Flags = 2 then
- begin
- Libmat.Material.FaceCulling := FcNoCull;
- Libmat.Material.BlendingMode := BmTransparency;
- end;
- if AMat.MaterialData.Alpha <> 1 then
- begin
- Libmat.Material.Texture.ImageAlpha := TiaAlphaFromIntensity;
- Libmat.Material.Texture.TextureFormat := TfRGBA;
- Libmat.Material.Texture.TextureMode := TmModulate;
- end;
- end;
- end;
- // add lightmap material
- if (Assigned(LightLib)) and (Assigned(ALightmap)) then
- begin
- LightName := ALightmap.GetTextureName;
- // add base material
- LibMat := LightLib.Materials.GetLibMaterialByName(LightName
- { + IntToStr(MaterialNum) } );
- if not Assigned(LibMat) then
- begin
- if not FileExists(LightName) then
- LightName := ExtractFileName(LightName);
- LibMat := LightLib.AddTextureMaterial(LightName
- { + IntToStr(MaterialNum) } , LightName, False);
- LibMat.Material.Texture.TextureMode := TmReplace;
- if Assigned(ALightMap) then
- begin
- LibMat.TextureOffset.AsAffineVector :=
- AffineVectorMake(ALightMap.TextureData.X_pos,
- ALightMap.TextureData.Y_pos, 0);
- LibMat.TextureScale.AsAffineVector :=
- AffineVectorMake(ALightMap.TextureData.X_scale,
- ALightMap.TextureData.Y_scale, 1);
- end;
- end;
- // modify the material lightmap index
- AMat.MaterialData.Texture_id[1] := LibMat.Index;
- end;
- end
- else
- Result := '';
- end
- else
- Result := '';
- end;
- begin
- B3d := TFileB3D.Create;
- try
- // first, load the b3d model sturctures from stream
- B3d.LoadFromStream(AStream);
- // then add all the materials and lightmaps from b3d structures
- for I := 0 to B3d.Materials.Count - 1 do
- begin
- B3DMat := TB3DMaterial(B3d.Materials.Objects[I]);
- B3DTex := nil;
- B3DLightTex := nil;
- // check if there is one texture layer
- if B3DMat.MaterialData.N_texs > 0 then
- begin
- if B3DMat.MaterialData.Texture_id[0] >= 0 then
- B3DTex := TB3DTexture(B3d.Textures.Objects
- [B3DMat.MaterialData.Texture_id[0]]);
- // check if there are two texture layer
- if B3DMat.MaterialData.N_texs > 1 then
- // why lightmap in some case on channel 2?
- if B3DMat.MaterialData.Texture_id[1] >= 0 then
- B3DLightTex :=
- TB3DTexture(B3d.Textures.Objects
- [B3DMat.MaterialData.Texture_id[1]])
- else
- { //check if there are three texture layer }
- if B3DMat.MaterialData.N_texs > 2 then
- if B3DMat.MaterialData.Texture_id[2] >= 0 then
- B3DLightTex :=
- TB3DTexture(B3d.Textures.Objects
- [B3DMat.MaterialData.Texture_id[2]]);
- end;
- GetOrAllocateMaterial(I, B3DMat, B3DTex, B3DLightTex);
- end;
- if GetOwner is TgxBaseMesh then
- (GetOwner as TgxBaseMesh).NormalsOrientation := MnoDefault;
- Node := B3d.Nodes.NodeData;
- while Node <> nil do
- begin
- if Node^.Meshes <> nil then
- begin
- Mo := TgxMeshObject.CreateOwned(Owner.MeshObjects);
- SetString(S, Node^.Name, Strlen(Node^.Name));
- // if Pos('16', s)>1 then
- // Pos('17', s);
- Mo.Name := S;
- Mo.Mode := MomFaceGroups;
- // add all the vertices, normals, colors and texture-coords(including the lightmap texture)
- Vertex := Node^.Meshes^.Vertices.Vertices;
- while Assigned(Vertex) do
- begin
- // W3D modif inversed z
- Mo.Vertices.Add(AffineVectorMake(Vertex^.Y, Vertex^.X, Vertex^.Z));
- if (Node^.Meshes^.Vertices.Flags and 1) > 0 then
- Mo.Normals.Add(VectorNormalize(AffineVectorMake(Vertex^.Ny,
- Vertex^.Nx, Vertex^.Nz)));
- if (Node^.Meshes^.Vertices.Flags and 2) > 0 then
- begin
- Mo.Colors.Add(VectorMake(Vertex^.Red, Vertex^.Green, Vertex^.Blue,
- Vertex^.Alpha));
- end;
- case Node^.Meshes^.Vertices.Tex_coord_sets of
- 1:
- begin
- case Node^.Meshes^.Vertices.Tex_coord_set_size of
- 2:
- Mo.TexCoords.Add(Vertex^.Tex_coords[0],
- -Vertex^.Tex_coords[1], 0);
- 3:
- Mo.TexCoords.Add(Vertex^.Tex_coords[0],
- -Vertex^.Tex_coords[1], Vertex^.Tex_coords[2]);
- end;
- end;
- 2: // lightmap tex_coord included
- begin
- case Node^.Meshes^.Vertices.Tex_coord_set_size of
- 2:
- Mo.TexCoords.Add(Vertex^.Tex_coords[0],
- -Vertex^.Tex_coords[1], 0);
- 3:
- Mo.TexCoords.Add(Vertex^.Tex_coords[0],
- -Vertex^.Tex_coords[1], Vertex^.Tex_coords[2]);
- end;
- Mo.LightMapTexCoords.Add
- (Vertex^.Tex_coords
- [Node^.Meshes^.Vertices.Tex_coord_set_size],
- -Vertex^.Tex_coords
- [Node^.Meshes^.Vertices.Tex_coord_set_size + 1]);
- end;
- end;
- Vertex := Vertex^.Next;
- end;
- // add facegroups
- Triangles := Node^.Meshes^.Triangles;
- while Assigned(Triangles) do
- begin
- FaceGroup := TgxFGVertexIndexList.CreateOwned(Mo.FaceGroups);
- if Triangles^.Brush_id >= 0 then
- begin
- FaceGroup.MaterialName := B3d.Materials[Triangles^.Brush_id] +
- InttoStr(Triangles^.Brush_id);
- FaceGroup.LightMapIndex :=
- TB3DMaterial(B3d.Materials.Objects[Triangles^.Brush_id])
- .MaterialData.Texture_id[1];
- end
- else
- begin
- FaceGroup.MaterialName := '';
- FaceGroup.LightMapIndex := -1;
- end;
- for J := 0 to Length(Triangles^.Vertex_id) - 1 do
- FaceGroup.VertexIndices.Add(Triangles^.Vertex_id[J]);
- while FaceGroup.VertexIndices.Count mod 3 <> 0 do
- FaceGroup.VertexIndices.Delete(FaceGroup.VertexIndices.Count - 1);
- Triangles := Triangles.Next;
- FaceGroup.Reverse;
- end;
- RotQuat := QuaternionMake([Node^.Rotation.Z, Node^.Rotation.Y,
- Node^.Rotation.W], Node^.Rotation.X);
- RotMat := QuaternionToMatrix(RotQuat);
- Mo.Vertices.TransformAsVectors(RotMat);
- { mo.SetPosition( Node^.Position[1], Node^.Position[0], Node^.Position[2]);
- mo.SetScale( Node^.Scale[1], Node^.Scale[0], Node^.Scale[2]);
- }
- if Pos('ENT_', UpperCase(Mo.Name)) = 0 then
- V := AffineVectorMake(Node^.Position.Y,
- Node^.Position.X, Node^.Position.Z)
- else
- begin
- V := AffineVectorMake(0.0, 0.0, 0.0);
- end;
- V1 := AffineVectorMake(Node^.Scale.Y, Node^.Scale.X, Node^.Scale.Z);
- Matrix := CreateScaleAndTranslationMatrix(VectorMake(V1), VectorMake(V));
- Mo.Vertices.TransformAsPoints(Matrix);
- end;
- Node := Node^.Next;
- end;
- finally
- B3d.Free;
- end;
- end;
- initialization
- // ------------------------------------------------------------------
- // ------------------------------------------------------------------
- // ------------------------------------------------------------------
- RegisterVectorFileFormat('b3d', 'Blitz 3D model files', TgxB3DVectorFile);
- end.
|