| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- //
- // The graphics engine GLXEngine. The unit of GLScene for Delphi
- //
- unit GLS.File3DPDF;
- (* 3D PDF converter of GLScene's models *)
- interface
- uses
- WinApi.Windows,
- WinApi.ShellAPI,
- System.Classes,
- System.SysUtils,
- System.StrUtils,
- Stage.VectorTypes,
- GLS.PersistentClasses,
- Stage.VectorGeometry,
- GLS.VectorLists,
- GLS.VectorFileObjects,
- GLS.ApplicationFileIO,
- Stage.Utils;
- type
- (* The IDTF vector file (Intermediate Data Text File).
- Used for converting to IDTF -> U3D -> 3D PDF *)
- TGLIDTFVectorFile = class(TGLVectorFile)
- private
- procedure BuildNormals(m: TGLMeshObject);
- public
- class function Capabilities: TGLDataFileCapabilities; override;
- procedure SaveToStream(aStream: TStream); override;
- end;
- // The U3D vector file (using IDTF and U3DConverter).
- TGLU3DVectorFile = class(TGLIDTFVectorFile)
- public
- class function Capabilities: TGLDataFileCapabilities; override;
- procedure SaveToStream(aStream: TStream); override;
- end;
- var
- // global variable for accing the IDTF->U3D converter
- IDTFConverterFileName: string;
- //=========================================================
- implementation
- //=========================================================
- const
- ConstIDTFTemplate =
- ' FILE_FORMAT "IDTF" ' + #13#10 +
- ' FORMAT_VERSION 100 ' + #13#10 +
- ' ' + #13#10 +
- ' NODE "MODEL" { ' + #13#10 +
- ' NODE_NAME "VcgMesh01" ' + #13#10 +
- ' PARENT_LIST { ' + #13#10 +
- ' PARENT_COUNT 1 ' + #13#10 +
- ' PARENT 0 { ' + #13#10 +
- ' PARENT_NAME "<NULL>" ' + #13#10 +
- ' PARENT_TM { ' + #13#10 +
- ' 1.000000 0.000000 0.000000 0.000000 ' + #13#10 +
- ' 0.000000 1.000000 0.000000 0.000000 ' + #13#10 +
- ' 0.000000 0.000000 1.000000 0.000000 ' + #13#10 +
- ' 0.000000 0.000000 0.000000 1.000000 ' + #13#10 +
- ' } ' + #13#10 +
- ' } ' + #13#10 +
- ' } ' + #13#10 +
- ' RESOURCE_NAME "MyVcgMesh01" ' + #13#10 +
- ' } ' + #13#10 +
- ' ' + #13#10 +
- ' RESOURCE_LIST "MODEL" { ' + #13#10 +
- ' RESOURCE_COUNT 1 ' + #13#10 +
- ' RESOURCE 0 { ' + #13#10 +
- ' RESOURCE_NAME "MyVcgMesh01" ' + #13#10 +
- ' MODEL_TYPE "MESH" ' + #13#10 +
- ' MESH { ' + #13#10 +
- ' FACE_COUNT %d ' + #13#10 +
- ' MODEL_POSITION_COUNT %d ' + #13#10 +
- ' MODEL_NORMAL_COUNT %d ' + #13#10 +
- ' MODEL_DIFFUSE_COLOR_COUNT 0 ' + #13#10 +
- ' MODEL_SPECULAR_COLOR_COUNT 0 ' + #13#10 +
- ' MODEL_TEXTURE_COORD_COUNT 0 ' + #13#10 +
- ' MODEL_BONE_COUNT 0 ' + #13#10 +
- ' MODEL_SHADING_COUNT 1 ' + #13#10 +
- ' MODEL_SHADING_DESCRIPTION_LIST { ' + #13#10 +
- ' SHADING_DESCRIPTION 0 { ' + #13#10 +
- ' TEXTURE_LAYER_COUNT 0 ' + #13#10 +
- ' SHADER_ID 0 ' + #13#10 +
- ' } ' + #13#10 +
- ' } ' + #13#10 +
- ' MESH_FACE_POSITION_LIST { ' + #13#10 +
- ' %s ' + #13#10 +
- ' } ' + #13#10 +
- ' MESH_FACE_NORMAL_LIST { ' + #13#10 +
- ' %s ' + #13#10 +
- ' } ' + #13#10 +
- ' MESH_FACE_SHADING_LIST { ' + #13#10 +
- ' %s ' + #13#10 +
- ' } ' + #13#10 +
- ' MODEL_POSITION_LIST { ' + #13#10 +
- ' %s ' + #13#10 +
- ' } ' + #13#10 +
- ' MODEL_NORMAL_LIST { ' + #13#10 +
- ' %s ' + #13#10 +
- ' } ' + #13#10 +
- ' } ' + #13#10 +
- ' } ' + #13#10 +
- ' } ';
- var
- USFormat: TFormatSettings;
- // helper functions
- function SingleToStr(const AValue: Single): string; inline;
- begin
- if AValue = 0.0 then
- begin
- Result:= '0';
- Exit;
- end
- else
- // Limit to maxint
- if AValue > (MaxInt - 1) then
- Result:= '2147483647'
- else
- if AValue < -(MaxInt - 1) then
- Result:= '2147483647';
- Result:= FloatToStrF(AValue, ffFixed, 8, 6, USFormat);
- end;
- function GetTempPath: string;
- var
- Len: Integer;
- begin
- SetLastError(ERROR_SUCCESS);
- // get memory for the buffer retaining the temp path (plus null-termination)
- SetLength(Result, MAX_PATH);
- Len := Winapi.Windows.GetTempPath(MAX_PATH, PChar(Result));
- if Len <> 0 then
- begin
- Len := GetLongPathName(PChar(Result), nil, 0);
- GetLongPathName(PChar(Result), PChar(Result), Len);
- SetLength(Result, Len - 1);
- end
- else
- Result := '';
- end;
- procedure ExecProgramAndWait(const AProcessName, AParams: string);
- var
- startUpInfo : TStartupInfo;
- ProcessInfo : TProcessInformation;
- exeCmd : string;
- ExitCode: cardinal;
- begin
- // Concat in the parameters
- exeCmd := AProcessName + ' ' + AParams;
- // Initialise the StartUpInfo record, which handles the creation of
- // a new main window for a process
- FillChar(startUpInfo, SizeOf(startUpInfo), 0);
- StartUpInfo.cb := SizeOf( StartUpInfo );
- StartUpInfo.dwFlags := STARTF_USESHOWWINDOW;
- StartUpInfo.wShowWindow := SW_HIDE;
- // Spawn the process out.
- if CreateProcess(nil, PChar(exeCmd), nil, nil, false,
- CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
- PChar(ExtractFilePath(AProcessName)), startUpInfo, ProcessInfo) then
- begin
- // close the thread handle as soon as it is no longer needed
- CloseHandle(ProcessInfo.hThread);
- // Wait for the process to finish.
- if not WaitForSingleObject(ProcessInfo.hProcess, INFINITE) = WAIT_OBJECT_0 then
- raise Exception.CreateFmt('U3DConverter: %s', [SysErrorMessage(GetLastError)]);
- // finish process
- if GetExitCodeProcess(ProcessInfo.hProcess, ExitCode) then
- raise Exception.CreateFmt('U3DConverter failed with exitcode $%x', [ExitCode]);
- CloseHandle(ProcessInfo.hProcess);
- end
- else
- begin
- // create process failure
- raise Exception.CreateFmt('U3DConverter: %s', [SysErrorMessage(GetLastError)]);
- end;
- end;
- //=============================
- // TGLIDTFVectorFile
- //=============================
- class function TGLIDTFVectorFile.Capabilities: TGLDataFileCapabilities;
- begin
- Result := [dfcWrite];
- end;
- // build normals
- procedure TGLIDTFVectorFile.BuildNormals(m: TGLMeshObject);
- var
- i, j: Integer;
- v1, v2, v3, v4, n: TAffineVector;
- begin
- for i := 0 to m.vertices.count - 1 do
- m.Normals.Add(0, 0, 0);
- for i := 0 to m.FaceGroups.count - 1 do
- if m.FaceGroups[i] is TFGVertexIndexList then
- with m.FaceGroups[i] as TFGVertexIndexList do
- case mode of
- fgmmTriangles:
- begin
- for j := 0 to (VertexIndices.count div 3) - 1 do
- begin
- v1 := m.vertices[VertexIndices[j * 3]];
- v2 := m.vertices[VertexIndices[j * 3 + 1]];
- v3 := m.vertices[VertexIndices[j * 3 + 2]];
- n := CalcPlaneNormal(v1, v2, v3);
- m.Normals.items[VertexIndices[j * 3]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 3]], n);
- m.Normals.items[VertexIndices[j * 3 + 1]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 3 + 1]], n);
- m.Normals.items[VertexIndices[j * 3 + 2]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 3 + 2]], n);
- end;
- end;
- fgmmQuads:
- begin
- for j := 0 to (VertexIndices.count div 4) - 1 do
- begin
- v1 := m.vertices[VertexIndices[j * 4]];
- v2 := m.vertices[VertexIndices[j * 4 + 1]];
- v3 := m.vertices[VertexIndices[j * 4 + 2]];
- v4 := m.vertices[VertexIndices[j * 4 + 3]];
- n := CalcPlaneNormal(v1, v2, v3);
- m.Normals.items[VertexIndices[j * 4]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 4]], n);
- m.Normals.items[VertexIndices[j * 4 + 1]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 4 + 1]], n);
- m.Normals.items[VertexIndices[j * 4 + 2]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 4 + 2]], n);
- m.Normals.items[VertexIndices[j * 4 + 3]] :=
- VectorAdd(m.Normals.items[VertexIndices[j * 4 + 3]], n);
- end;
- end;
- end;
- for i := 0 to m.Normals.count - 1 do
- m.Normals.items[i] := VectorNormalize(m.Normals.items[i]);
- end;
- procedure TGLIDTFVectorFile.SaveToStream(aStream: TStream);
- var
- S: String;
- Mesh: TGLMeshObject;
- FaceCount, ModelPositionCount, NormalCount, I, J: Integer;
- FacePositionList, NormalList, ModelPositionList, ModelNormalList, FaceShadingList: String;
- Lines: TStringList;
- Indicies: TGLIntegerList;
- function FormatVector(const AVector: TAffineVector): string;
- begin
- Result:= SingleToStr(AVector.X) + ' ' + SingleToStr(AVector.Y) + ' ' + SingleToStr(AVector.Z);
- end;
- begin
- // ++ todo: save more than one mesh
- Mesh:= Owner.MeshObjects[0];
- // BuildNormals(Mesh);
- // count
- NormalList:= '';
- ModelNormalList:= '';
- // faces
- // MESH_FACE_POSITION_LIST
- FaceCount:= 0;
- FacePositionList:= '';
- for i := 0 to Mesh.FaceGroups.count - 1 do
- if Mesh.FaceGroups[i] is TFGVertexIndexList then
- with Mesh.FaceGroups[i] as TFGVertexIndexList do
- begin
- // face indicies
- Indicies:= TFGVertexIndexList(Mesh.FaceGroups[i]).VertexIndices;
- Inc(FaceCount, Indicies.Count div 3);
- J:= 0;
- while J < Indicies.Count do
- begin
- FacePositionList:= FacePositionList + ' ' + Format('%d %d %d', [Indicies[J +2], Indicies[J +1], Indicies[J]]) + #13#10;
- inc(J, 3);
- end;
- end;
- FacePositionList:= Trim(FacePositionList);
- FaceShadingList:= '';
- for i := 1 to FaceCount do
- FaceShadingList:= FaceShadingList + ' 0' + #13#10;
- FaceShadingList:= Trim(FaceShadingList);
- // verticies
- ModelPositionList:= '';
- ModelPositionCount:= Mesh.Vertices.Count;
- for I:= 0 to Pred(Mesh.Vertices.Count) do
- ModelPositionList:= ModelPositionList + ' ' + FormatVector(Mesh.Vertices[I]) + #13#10;
- ModelPositionList:= Trim(ModelPositionList);
- // points
- // normals
- // FMeshObject.BuildNormals(FMeshObject.Vertices., momFaceGroups); ++
- NormalCount:= Mesh.Normals.Count;
- NormalList:= '';
- for I:= 0 to Pred(Mesh.Normals.Count) do
- NormalList:= NormalList + ' ' + FormatVector(Mesh.Normals[I]) + #13#10;
- NormalList:= Trim(NormalList);
- // build the IDTF file
- S:= Format(ConstIDTFTemplate, [FaceCount, ModelPositionCount, NormalCount,
- FacePositionList, NormalList, FaceShadingList, ModelPositionList, ModelNormalList]);
- ;
- Lines:= TStringList.Create;
- try
- Lines.Text:= S;
- Lines.SaveToStream(aStream, TEncoding.ASCII);
- finally
- Lines.Free;
- end;
- end;
- //==================================
- // TGLU3DVectorFile
- //==================================
- class function TGLU3DVectorFile.Capabilities: TGLDataFileCapabilities;
- begin
- Result := [dfcWrite];
- end;
- procedure TGLU3DVectorFile.SaveToStream(aStream: TStream);
- var
- TempStream: TStream;
- TempInFile, TempOutFile, Params: String;
- begin
- TempInFile:= IncludeTrailingPathDelimiter(GetTempPath) + 'GLObject.idtf';
- // save as temp .idtf file
- TempStream:= TFileStream.Create(TempInFile, fmCreate);
- try
- inherited SaveToStream(TempStream);
- finally
- TempStream.Free;
- end;
- // convert IDTF to U3D using U3DConverter
- TempOutFile:= ChangeFileExt(TempInFile, '.u3d');
- Params:= Format('-i "%s" -o "%s"', [TempInFile, TempOutFile]);
- ExecProgramAndWait(IDTFConverterFileName, Params);
- // copy U3D file to stream
- TempStream:= TFileStream.Create(TempOutFile, fmOpenRead or fmShareDenyWrite);
- try
- AStream.CopyFrom(TempStream, 0);
- finally
- TempStream.Free;
- end;
- DeleteFile(TempInFile);
- DeleteFile(TempOutFile);
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- USFormat:= TFormatSettings.Create('en_us');
- IDTFConverterFileName:= IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'IDTFConverter.exe';
- // register formats
- RegisterVectorFileFormat('idtf', 'Intermediate Data Text File', TGLIDTFVectorFile);
- RegisterVectorFileFormat('u3d', 'Universal 3D', TGLU3DVectorFile);
- end.
|