MathgeomGLS
414 строк · 10.3 Кб
1unit fDelaunayFF;
2
3interface
4
5uses
6Winapi.Windows,
7Winapi.Messages,
8Winapi.OpenGL,
9System.SysUtils,
10System.Variants,
11System.Classes,
12System.Math,
13System.IniFiles,
14Vcl.Graphics,
15Vcl.Controls,
16Vcl.Forms,
17Vcl.Dialogs,
18Vcl.ComCtrls,
19Vcl.StdCtrls,
20Vcl.ExtCtrls,
21Vcl.Imaging.Jpeg,
22
23GLS.PersistentClasses,
24GLS.Scene,
25GLS.Objects,
26GLS.Mesh,
27GLS.Texture,
28GLS.VectorTypes,
29GLS.VectorGeometry,
30GLS.VectorFileObjects,
31GLS.VectorLists,
32GLS.MeshUtils,
33GLS.Cadencer,
34
35GLS.Context,
36GLS.HUDObjects,
37GLS.File3DS,
38GLS.SceneViewer,
39GLS.Material,
40GLS.Coordinates,
41GLS.BaseClasses,
42GLS.RenderContextInfo,
43GLS.State,
44GLS.Triangulation,
45GLS.Utils;
46
47type
48TForm1 = class(TForm)
49GLScene: TGLScene;
50GLLightSource1: TGLLightSource;
51Panel1: TPanel;
52GroupBox1: TGroupBox;
53Label3: TLabel;
54SmoothTB: TTrackBar;
55SubdivideBtn: TButton;
56GroupBox2: TGroupBox;
57WireframeCB: TCheckBox;
58Timer1: TTimer;
59GLSceneViewer1: TGLSceneViewer;
60GLCadencer: TGLCadencer;
61TimeLabel: TLabel;
62TexturedCB: TCheckBox;
63GLDirectOpenGL1: TGLDirectOpenGL;
64MatLib: TGLMaterialLibrary;
65ffWindrose: TGLFreeForm;
66CamH: TGLDummyCube;
67CamV: TGLDummyCube;
68Camera: TGLCamera;
69ffTerrain: TGLFreeForm;
70procedure FormCreate(Sender: TObject);
71procedure FormDestroy(Sender: TObject);
72procedure SubdivideBtnClick(Sender: TObject);
73procedure WireframeCBClick(Sender: TObject);
74procedure Timer1Timer(Sender: TObject);
75procedure GLCadencerProgress(Sender: TObject;
76const deltaTime, newTime: Double);
77procedure TexturedCBClick(Sender: TObject);
78procedure GLDirectOpenGL1Render(Sender: TObject;
79var rci: TGLRenderContextInfo);
80procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
81Shift: TShiftState; X, Y: Integer);
82procedure GLSceneViewer1MouseUp(Sender: TObject; Button: TMouseButton;
83Shift: TShiftState; X, Y: Integer);
84procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
85WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
86private
87mx, my: Integer;
88MousePos: TPoint;
89t: Int64;
90IsLeftMouseDown, IsRightMouseDown: Boolean;
91procedure BuildMesh(TargetMesh: TGLFreeForm; D: TGLDelaunay2D);
92procedure SubdivideMesh(TargetMesh: TGLFreeForm; Smooth: Single);
93public
94end;
95
96var
97MeshObj: TGLMeshObject;
98Delaunay2D: TGLDelaunay2D;
99Form1: TForm1;
100
101implementation
102
103{$R *.dfm}
104
105procedure TForm1.FormCreate(Sender: TObject);
106var
107Ini: TIniFile;
108i: Integer;
109X, Y, z, u, v: Single;
110ExePath: TFileName;
111AMatIndex: Integer;
112S: String;
113
114begin
115ExePath := ExtractFilePath(ParamStr(0));
116ffTerrain.Material.Texture.Image.LoadFromFile('terr3.jpg');
117Ini := TIniFile.Create(ExePath + 'Vertexes.ini');
118Delaunay2D := TGLDelaunay2D.Create;
119
120for i := 0 to 559 do
121begin
122S := IntToStr(i);
123X := Ini.ReadFloat(S, 'X', 0.0);
124Y := Ini.ReadFloat(S, 'Y', 0.0);
125z := Ini.ReadFloat(S, 'Z', 0.0);
126u := Ini.ReadFloat(S, 'U', 0.0);
127v := Ini.ReadFloat(S, 'V', 0.0);
128AMatIndex := 0; // no material
129Delaunay2D.AddPoint(X, Y, z, u, v, AMatIndex);
130end;
131t := StartPrecisionTimer;
132Delaunay2D.Mesh(True);
133BuildMesh(ffTerrain, Delaunay2D);
134Ini.Free;
135TimeLabel.Caption := Format('Delaunay triangulation completed in %.1f ms' +
136#10#13, [StopPrecisionTimer(t) * 1000]);
137ffWindrose.LoadFromFile('windrose.3ds');
138end;
139
140procedure TForm1.FormDestroy(Sender: TObject);
141begin
142Delaunay2D.Free;
143end;
144
145procedure TForm1.BuildMesh(TargetMesh: TGLFreeForm; D: TGLDelaunay2D);
146var
147i: Integer;
148vert1, vert2, vert3: DVertex;
149FaceGroup: TFGVertexIndexList;
150begin
151TargetMesh.MeshObjects.Clear;
152
153MeshObj := TGLMeshObject.CreateOwned(TargetMesh.MeshObjects);
154MeshObj.Mode := momFaceGroups;
155
156FaceGroup := TFGVertexIndexList.CreateOwned(MeshObj.FaceGroups);
157
158for i := 1 to D.HowMany do
159begin
160vert1 := D.Vertex[D.Triangle[i].vv0];
161vert2 := D.Vertex[D.Triangle[i].vv1];
162vert3 := D.Vertex[D.Triangle[i].vv2];
163
164MeshObj.Vertices.Add(vert1.X, vert1.Y, vert1.z);
165MeshObj.Vertices.Add(vert2.X, vert2.Y, vert2.z);
166MeshObj.Vertices.Add(vert3.X, vert3.Y, vert3.z);
167
168MeshObj.Colors.Add(1.0, 0.0, 0.0, 1.0);
169MeshObj.Colors.Add(0.0, 1.0, 0.0, 1.0);
170MeshObj.Colors.Add(0.0, 0.0, 1.0, 1.0);
171
172MeshObj.TexCoords.Add(vert1.u, vert1.v);
173MeshObj.TexCoords.Add(vert2.u, vert2.v);
174MeshObj.TexCoords.Add(vert3.u, vert3.v);
175
176FaceGroup.Add(MeshObj.Vertices.Count - 1);
177FaceGroup.Add(MeshObj.Vertices.Count - 2);
178FaceGroup.Add(MeshObj.Vertices.Count - 3);
179end;
180
181MeshObj.BuildNormals(FaceGroup.VertexIndices, momTriangles);
182
183TargetMesh.StructureChanged;
184end;
185
186procedure TForm1.SubdivideMesh(TargetMesh: TGLFreeForm; Smooth: Single);
187var
188i: Integer;
189tris, norms, tex, buf: TGLAffineVectorList;
190indices, texIndices: TGLIntegerList;
191MatName: String;
192begin
193for i := 0 to TargetMesh.MeshObjects.Count - 1 do
194begin
195tex := TGLAffineVectorList.Create;
196with TargetMesh.MeshObjects[i] do
197begin
198tris := ExtractTriangles(tex);
199end;
200indices := BuildVectorCountOptimizedIndices(tris);
201RemapAndCleanupReferences(tris, indices);
202
203norms := BuildNormals(tris, indices);
204
205// subdivide geometry
206SubdivideTriangles(Smooth, tris, indices, norms);
207
208texIndices := BuildVectorCountOptimizedIndices(tex);
209RemapAndCleanupReferences(tex, texIndices);
210
211// subdivide texture space
212SubdivideTriangles(0, tex, texIndices);
213
214// Re-expand everything
215buf := TGLAffineVectorList.Create;
216try
217ConvertIndexedListToList(tris, indices, buf);
218tris.Assign(buf);
219buf.Count := 0;
220ConvertIndexedListToList(norms, indices, buf);
221norms.Assign(buf);
222buf.Count := 0;
223ConvertIndexedListToList(tex, texIndices, buf);
224tex.Assign(buf);
225finally
226buf.Free;
227end;
228
229// Pack & Optimize the expanded stuff
230
231indices.Free;
232indices := BuildVectorCountOptimizedIndices(tris, norms, tex);
233
234RemapReferences(norms, indices);
235RemapReferences(tex, indices);
236RemapAndCleanupReferences(tris, indices);
237
238IncreaseCoherency(indices, 13);
239
240with TargetMesh.MeshObjects[i] do
241begin
242Vertices := tris;
243Normals := norms;
244TexCoords := tex;
245
246MatName := FaceGroups.Items[0].MaterialName;
247FaceGroups.Clear;
248with TFGVertexIndexList.CreateOwned(FaceGroups) do
249begin
250MaterialName := MatName;
251VertexIndices := indices;
252Mode := fgmmTriangles;
253end;
254end;
255
256texIndices.Free;
257tex.Free;
258indices.Free;
259norms.Free;
260tris.Free;
261end;
262
263TargetMesh.StructureChanged;
264end;
265
266procedure TForm1.SubdivideBtnClick(Sender: TObject);
267begin
268t := StartPrecisionTimer;
269SubdivideMesh(ffTerrain, SmoothTB.Position / 10);
270TimeLabel.Caption := TimeLabel.Caption +
271Format('Subdivide completed in %.1f ms' + #10#13,
272[StopPrecisionTimer(t) * 1000]);
273end;
274
275procedure TForm1.WireframeCBClick(Sender: TObject);
276begin
277if (WireframeCB.Checked) then
278ffTerrain.Material.PolygonMode := pmLines
279else
280begin
281ffTerrain.Material.PolygonMode := pmFill;
282end;
283end;
284
285procedure TForm1.Timer1Timer(Sender: TObject);
286begin
287Caption := Format('%.1f FPS - %d Triangles', [GLSceneViewer1.FramesPerSecond,
288ffTerrain.MeshObjects.TriangleCount]);
289GLSceneViewer1.ResetPerformanceMonitor;
290end;
291
292procedure TForm1.GLCadencerProgress(Sender: TObject;
293const deltaTime, newTime: Double);
294var
295deltax, deltay: Single;
296pt: TPoint;
297begin
298if (IsLeftMouseDown or IsRightMouseDown) then
299begin
300GetCursorPos(pt);
301deltax := (MousePos.X - pt.X) / 5;
302deltay := (MousePos.Y - pt.Y) / 5;
303if (pt.X <> MousePos.X) or (pt.Y <> MousePos.Y) then
304SetCursorPos(MousePos.X, MousePos.Y);
305end;
306
307// rotate
308if IsLeftMouseDown then
309begin
310CamH.TurnAngle := CamH.TurnAngle + deltax;
311if CamH.TurnAngle >= 360 then
312CamH.TurnAngle := CamH.TurnAngle - 360;
313if CamH.TurnAngle < 0 then
314CamH.TurnAngle := CamH.TurnAngle + 360;
315
316// rotation of camera in half sphere
317if (CamV.PitchAngle - deltay < 89) and (CamV.PitchAngle - deltay > 0) then
318CamV.PitchAngle := CamV.PitchAngle - deltay;
319end
320else
321begin
322// moving camera (pan)
323if IsRightMouseDown then
324begin
325CamH.Move(-50 * deltay * deltaTime);
326CamH.Slide(50 * deltax * deltaTime);
327end;
328end;
329
330GLSceneViewer1.Invalidate;
331end;
332
333procedure TForm1.TexturedCBClick(Sender: TObject);
334begin
335ffTerrain.Material.Texture.Enabled := TexturedCB.Checked;
336end;
337
338procedure TForm1.GLDirectOpenGL1Render(Sender: TObject;
339var rci: TGLRenderContextInfo);
340var
341size: Single;
342begin
343glPushAttrib(GL_ALL_ATTRIB_BITS);
344glMatrixMode(GL_PROJECTION);
345glPushMatrix;
346glLoadIdentity;
347glOrtho(0, GLSceneViewer1.Width, 0, GLSceneViewer1.Height, -1000, 1000);
348glMatrixMode(GL_MODELVIEW);
349glLoadIdentity;
350
351GLScene.SetupLights(GLScene.CurrentBuffer.LimitOf[limLights]);
352
353size := GLSceneViewer1.Height / 6;
354
355ffWindrose.ResetRotations;
356ffWindrose.PitchAngle := -CamV.PitchAngle + 90;
357ffWindrose.RollAngle := -CamH.TurnAngle;
358
359ffWindrose.Position.AsVector := VectorMake(size, size, 0);
360ffWindrose.Scale.AsVector := VectorMake(size, size, size);
361
362ffWindrose.Render(rci);
363
364glMatrixMode(GL_PROJECTION);
365glPopMatrix;
366glMatrixMode(GL_MODELVIEW);
367glPopAttrib;
368end;
369
370procedure TForm1.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
371Shift: TShiftState; X, Y: Integer);
372begin
373if (ssRight in Shift) then
374IsRightMouseDown := True;
375
376if (ssLeft in Shift) then
377begin
378mx := X;
379my := Y;
380IsLeftMouseDown := True;
381end;
382
383Screen.Cursor := crNone;
384GetCursorPos(MousePos);
385end;
386
387procedure TForm1.GLSceneViewer1MouseUp(Sender: TObject; Button: TMouseButton;
388Shift: TShiftState; X, Y: Integer);
389begin
390if Button = TMouseButton(mbLeft) then
391IsLeftMouseDown := False;
392
393if Button = TMouseButton(mbRight) then
394IsRightMouseDown := False;
395
396if not((ssLeft in Shift) or (ssRight in Shift)) then
397Screen.Cursor := crDefault;
398end;
399
400procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
401WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
402var
403DistDelta: Single;
404begin
405with Camera do
406begin
407DistDelta := Power(1.1, WheelDelta / 240);
408
409if (DistanceToTarget > 10) or (WheelDelta > 0) then
410AdjustDistanceToTarget(DistDelta);
411end;
412end;
413
414end.
415