2
Copyright 2002-2013 Michalis Kamburelis.
4
This file is part of "Castle Game Engine".
6
"Castle Game Engine" is free software; see the file COPYING.txt,
7
included in this distribution, for details about the copyright.
9
"Castle Game Engine" is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
----------------------------------------------------------------------------
16
{ Load 3D Videoscape GEO models.
17
See [http://local.wasp.uwa.edu.au/~pbourke/dataformats/geo/].
18
We handle basic geometry, we can open files exported by Blender exporter. }
19
unit X3DLoadInternalGEO;
25
function LoadGEO(const filename: string): TX3DRootNode;
29
uses CastleVectors, CastleUtils, Classes, SysUtils,
30
CastleFilesUtils, CastleStringUtils, X3DLoadInternalUtils;
32
{ TObject3DGEO ---------------------------------------------------------------- }
35
{ Reader of GEO files.
36
Note that contents of Verts and Faces are read-only for user of this unit. }
39
Verts: TVector3SingleList;
40
Faces: TVector3CardinalList;
41
constructor Create(const fname: string);
42
destructor Destroy; override;
45
constructor TObject3DGEO.Create(const fname: string);
47
TGEOFormatFlavor = (gfOld, gfMeshColorFaces, gfMeshColorVerts);
49
Flavor: TGEOFormatFlavor;
51
function ReadVertexIndex(var F: TextFile): Cardinal;
54
{ In older format, vertex index is 1-based. }
55
if Flavor = gfOld then Dec(Result);
58
{ Read exactly one line of GEO file, reading new face information.
60
procedure ReadGEOFace(var F: TextFile);
62
J, ThisPolyCount: Integer;
63
FirstVert, LastVert: Cardinal;
64
CurrentFace: PVector3Cardinal;
66
Read(F, ThisPolyCount);
68
CurrentFace := Faces.Add;
70
{ odczytaj "na pewniaka" pierwszy trojkat }
72
CurrentFace^[j] := ReadVertexIndex(F);
74
FirstVert := CurrentFace^[0];
75
LastVert := CurrentFace^[2];
77
{ dla kazdego nastepnego vertexa polygonu tworz nowy trojkat jako
78
sklejenie FirstVert, LastVert i nowego vertexa. Pilnuj kolejnosci
79
aby wszystkie trojkaty z tego polygonu byly tak zorientowane jak ten
81
for j := 3 to ThisPolyCount - 1 do
83
CurrentFace := Faces.Add;
85
CurrentFace^[0] := FirstVert;
86
CurrentFace^[1] := LastVert;
87
CurrentFace^[2] := ReadVertexIndex(F);
89
LastVert := CurrentFace^[2];
98
VertsCount, PolysCount, VertsInPolysCount: Integer;
101
Verts := TVector3SingleList.Create;
102
Faces := TVector3CardinalList.Create;
104
SafeReset(f, fname, true);
106
{ Read first line: magic number (or not existent in older GEO format) }
109
if SameText(Line, '3DG1') then
110
Flavor := gfMeshColorFaces else
111
if SameText(Line, 'GOUR') then
112
Flavor := gfMeshColorVerts else
115
if Flavor = gfOld then
117
{ Use current value of Line, for older format the first line contains
119
DeFormat(Line, '%d %d %d', [@VertsCount, @PolysCount, @VertsInPolysCount]);
121
{ Ile mamy Faces trojkatnych ? Mamy liczbe
122
wielokatow = PolysCount. Mamy sumaryczna liczbe wierzcholkow
123
w nich. Na kazdy polygon przypadaja co najmniej 3 wierzcholki
124
i one daja jeden trojkat. Kazdy nadmiarowy wierzcholek,
125
bez wzgledu na to w ktorym polygonie sie znajdzie, spowoduje
126
utworzenie nowego trojkata. Stad
127
FFacesCount := PolysCount + (VertsInPolysCount - PolysCount * 3);
129
Faces.SetLength(VertsInPolysCount - PolysCount * 2);
131
To cooperate with other Flavor, we do not set Faces.Count directly,
132
instead we set only Capacity.
134
Faces.Capacity := VertsInPolysCount - PolysCount * 2;
137
{ In newer formats, 2nd line contains just VertsCount. }
138
Readln(F, VertsCount);
142
Verts.Count := VertsCount;
143
for i := 0 to Verts.Count-1 do
144
Readln(f, Verts.L[i][0], Verts.L[i][1], Verts.L[i][2]);
146
if PolysCount <> -1 then
148
for i := 0 to PolysCount - 1 do
152
{ PolysCount not known. So we just read the file as fas as we can. }
153
while not SeekEof(F) do
156
finally CloseFile(f) end;
159
destructor TObject3DGEO.Destroy;
166
{ LoadGEO -------------------------------------------------------------------- }
168
function LoadGEO(const filename: string): TX3DRootNode;
171
verts: TCoordinateNode;
172
faces: TIndexedFaceSetNode;
177
BaseUrl := ExtractFilePath(ExpandFilename(filename));
178
geo := TObject3DGEO.Create(filename);
180
result := TX3DRootNode.Create('', BaseUrl);
182
Result.HasForceVersion := true;
183
Result.ForceVersion := X3DVersion;
185
Shape := TShapeNode.Create('', BaseUrl);
186
result.FdChildren.Add(Shape);
187
Shape.Material := TMaterialNode.Create('', BaseUrl);
189
faces := TIndexedFaceSetNode.Create('', BaseUrl);
190
Shape.FdGeometry.Value := faces;
191
faces.FdCreaseAngle.Value := NiceCreaseAngle;
192
faces.FdSolid.Value := false;
193
faces.FdCoordIndex.Count := geo.Faces.Count * 4;
194
for i := 0 to geo.Faces.Count-1 do
196
faces.FdCoordIndex.Items.L[i * 4 ] := geo.Faces.L[i][0];
197
faces.FdCoordIndex.Items.L[i * 4 + 1] := geo.Faces.L[i][1];
198
faces.FdCoordIndex.Items.L[i * 4 + 2] := geo.Faces.L[i][2];
199
faces.FdCoordIndex.Items.L[i * 4 + 3] := -1;
202
verts := TCoordinateNode.Create('', BaseUrl);
203
faces.FdCoord.Value := verts;
204
verts.FdPoint.Items.Assign(geo.Verts);
205
except result.Free; raise end;
206
finally geo.Free end;