Merge remote-tracking branch 'glBitmap@DGL/master'
[LazOpenGLCore.git] / uglcCamera.pas
1 unit uglcCamera;
2
3 { Package:      OpenGLCore
4   Prefix:       glc - OpenGL Core
5   Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Frustum und Kamera
6   Beispiel:
7     var
8       camera: TglcCamera;
9
10     camera := TglcCamera.Create;
11     try
12       camera.Perspective(45, 0.01, 100, 800/600);   // define perspective view
13       camera.Move(gluVector(2, 3, -5));             // move 2 right, 3 up and 5 back
14       camera.Tilt(-25);                             // turn 25 degrees down
15       camera.Turn(-10);                             // turn 10 degrees left
16       camera.Activate;                              // activate camera
17
18       // do normal rendering
19
20     finally
21       FreeAndNil(camera);
22     end;  }
23
24 {$mode objfpc}{$H+}
25
26 interface
27
28 uses
29   Classes, SysUtils,
30   ugluVector, ugluMatrix;
31
32 type
33 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34   TglcFrustum = class(TObject)
35   private
36     fProjMatrix: TgluMatrix4f;
37     function GetProjMatrixPtr: Pointer;
38     function GetWidth: Single;
39     function GetHeight: Single;
40     function GetFOVAngle: Single;
41     function GetAspectRatio: Single;
42     procedure UpdateProjMatrix;
43   protected
44     fIsOrthogonal: Boolean;
45     fTop, fBottom, fLeft, fRight, fNear, fFar: Single;
46   public
47     property Top:           Single        read fTop;
48     property Bottom:        Single        read fBottom;
49     property Left:          Single        read fLeft;
50     property Right:         Single        read fRight;
51     property Near:          Single        read fNear;
52     property Far:           Single        read fFar;
53     property Width:         Single        read GetWidth;
54     property Height:        Single        read GetHeight;
55     property FOVAngle:      Single        read GetFOVAngle;
56     property AspectRatio:   Single        read GetAspectRatio;
57     property IsOrthogonal:  Boolean       read fIsOrthogonal;
58     property ProjMatrix:    TgluMatrix4f  read fProjMatrix;
59     property ProjMatrixPtr: Pointer       read GetProjMatrixPtr;
60
61     procedure Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
62     procedure Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single);
63     procedure Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
64     procedure Activate;
65 {$IFNDEF OPENGL_ES}
66     procedure Render;
67 {$ENDIF}
68
69     constructor Create;
70   end;
71
72 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
73   TglcCamera = class(TglcFrustum)
74   private
75     fPosition: TgluMatrix4f;
76     function GetPositionPtr: Pointer;
77   public
78     property Position:    TgluMatrix4f read fPosition write fPosition;
79     property PositionPtr: Pointer      read GetPositionPtr;
80
81     procedure Move(const aVec: TgluVector3f);
82     procedure Tilt(const aAngle: Single);
83     procedure Turn(const aAngle: Single);
84     procedure Roll(const aAngle: Single);
85     procedure Activate;
86     function GetRay(const aPos: TgluVector2f): TgluRayf;
87
88     constructor Create;
89   end;
90
91 implementation
92
93 uses
94   Math, {$IFNDEF OPENGL_ES}dglOpenGL{$ELSE}dglOpenGLES{$ENDIF};
95
96
97 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
98 //TglcFrustum///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
99 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100 procedure TglcFrustum.UpdateProjMatrix;
101 begin
102   if fIsOrthogonal then begin
103     fProjMatrix[maAxisX] := gluVector4f(
104       2 / (fRight - fLeft),
105       0,
106       0,
107       0);
108     fProjMatrix[maAxisY] := gluVector4f(
109       0,
110       2 / (fTop - fBottom),
111       0,
112       0);
113     fProjMatrix[maAxisZ] := gluVector4f(
114       0,
115       0,
116       -2 / (fFar - fNear),
117       0);
118     fProjMatrix[maPos] := gluVector4f(
119       -(fRight + fLeft)   / (fRight - fLeft),
120       -(fTop   + fBottom) / (fTop   - fBottom),
121       -(fFar   + fNear)   / (fFar   - fNear),
122       1);
123   end else begin
124     fProjMatrix[maAxisX] := gluVector4f(
125       2 * fNear / (fRight - fLeft),
126       0,
127       0,
128       0);
129     fProjMatrix[maAxisY] := gluVector4f(
130       0,
131       2 * fNear / (fTop   - fBottom),
132       0,
133       0);
134     fProjMatrix[maAxisZ] := gluVector4f(
135       (fRight + fLeft) / (fRight - fLeft),
136       (fTop + fBottom) / (fTop - fBottom),
137       -(fFar + fNear) / (fFar - fNear),
138       -1);
139     fProjMatrix[maPos] := gluVector4f(
140       0,
141       0,
142       -2 * fFar * fNear / (fFar - fNear),
143       0);
144   end;
145 end;
146
147 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
148 function TglcFrustum.GetWidth: Single;
149 begin
150   result := (fRight - fLeft);
151 end;
152
153 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154 function TglcFrustum.GetProjMatrixPtr: Pointer;
155 begin
156   result := @fProjMatrix[0, 0];
157 end;
158
159 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 function TglcFrustum.GetHeight: Single;
161 begin
162   result := (fTop - fBottom);
163 end;
164
165 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
166 function TglcFrustum.GetFOVAngle: Single;
167 begin
168   result := arctan2(Height/2, fNear)/Pi*360;
169 end;
170
171 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172 function TglcFrustum.GetAspectRatio: Single;
173 begin
174   result := Height / Width;
175 end;
176
177 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
178 procedure TglcFrustum.Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
179 begin
180   fIsOrthogonal := false;
181   fTop          := aRight;
182   fBottom       := aLeft;
183   fLeft         := aBottom;
184   fRight        := aTop;
185   fNear         := aNear;
186   fFar          := aFar;
187   UpdateProjMatrix;
188 end;
189
190 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
191 procedure TglcFrustum.Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single);
192 begin
193   fIsOrthogonal := false;
194   fNear         := aNear;
195   fFar          := aFar;
196   fTop          := fNear * tan(aFOVAngle / 360 * Pi);
197   fBottom       := -fTop;
198   fRight        := aAspectRatio * fTop;
199   fLeft         := -fRight;
200   UpdateProjMatrix;
201 end;
202
203 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
204 procedure TglcFrustum.Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
205 begin
206   fIsOrthogonal := true;
207   fLeft         := aLeft;
208   fRight        := aRight;
209   fTop          := aTop;
210   fBottom       := aBottom;
211   fNear         := aNear;
212   fFar          := aFar;
213   UpdateProjMatrix;
214 end;
215
216 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
217 procedure TglcFrustum.Activate;
218 begin
219   glMatrixMode(GL_PROJECTION);
220   glLoadIdentity;
221   if fIsOrthogonal then
222     {$IFNDEF OPENGL_ES}glOrtho{$ELSE}glOrthof{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar)
223   else
224     {$IFNDEF OPENGL_ES}glFrustum{$ELSE}glFrustumf{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar);
225   glMatrixMode(GL_MODELVIEW);
226 end;
227
228 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
229 {$IFNDEF OPENGL_ES}
230 procedure TglcFrustum.Render;
231 var
232   min, max: TgluVector2f;
233 begin
234   min[0] := fLeft   / fNear * fFar;
235   min[1] := fBottom / fNear * fFar;
236   max[0] := fRight  / fNear * fFar;
237   max[1] := fTop    / fNear * fFar;
238
239   glBegin(GL_LINE_LOOP);
240     glVertex3f(fLeft, fTop, -fNear);
241     glVertex3f(fLeft, fBottom, -fNear);
242     glVertex3f(fRight, fBottom, -fNear);
243     glVertex3f(fRight, fTop, -fNear);
244   glEnd;
245
246   glBegin(GL_LINE_LOOP);
247     glVertex3f(min[0], min[0], -fFar);
248     glVertex3f(min[0], max[0], -fFar);
249     glVertex3f(max[0], max[0], -fFar);
250     glVertex3f(max[0], min[0], -fFar);
251   glEnd;
252
253   glBegin(GL_LINES);
254     glVertex3f(0, 0, 0); glVertex3f(min[0], min[0], -fFar);
255     glVertex3f(0, 0, 0); glVertex3f(min[0], max[0], -fFar);
256     glVertex3f(0, 0, 0); glVertex3f(max[0], max[0], -fFar);
257     glVertex3f(0, 0, 0); glVertex3f(max[0], min[0], -fFar);
258   glEnd;
259 end;
260 {$ENDIF}
261
262 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
263 constructor TglcFrustum.Create;
264 begin
265   inherited Create;
266   fTop    := 0;
267   fBottom := 0;
268   fLeft   := 0;
269   fRight  := 0;
270   fNear   := 0;
271   fFar    := 0;
272 end;
273
274 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
275 //TglcCamera////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
277 function TglcCamera.GetPositionPtr: Pointer;
278 begin
279   result := @fPosition[0, 0];
280 end;
281
282 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
283 procedure TglcCamera.Move(const aVec: TgluVector3f);
284 begin
285   fPosition := gluMatrixMult(gluMatrixTranslate(aVec), fPosition);
286 end;
287
288 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
289 procedure TglcCamera.Tilt(const aAngle: Single);
290 begin
291   fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(1,0,0), aAngle), fPosition);
292 end;
293
294 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
295 procedure TglcCamera.Turn(const aAngle: Single);
296 begin
297   fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,1,0), aAngle), fPosition);
298 end;
299
300 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
301 procedure TglcCamera.Roll(const aAngle: Single);
302 begin
303   fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,0,1), aAngle), fPosition);
304 end;
305
306 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
307 procedure TglcCamera.Activate;
308 begin
309   inherited Activate;
310   glLoadMatrixf(@fPosition[0, 0]);
311 end;
312
313 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
314 function TglcCamera.GetRay(const aPos: TgluVector2f): TgluRayf;
315 var
316   p: TgluVector3f;
317 begin
318   if (aPos[0] < 0) then
319     p[0] := -aPos[0] * fLeft
320   else
321     p[0] := aPos[0] * fRight;
322   if (aPos[1] < 0) then
323     p[1] := -aPos[1] * fBottom
324   else
325     p[1] := aPos[1] * fTop;
326   if (fIsOrthogonal) then begin
327     p[2] := 0;
328     result.p := fPosition * p;
329     result.v := fPosition * gluVector3f(0, 0, -1);
330   end else begin
331     p[2] := -fNear;
332     result.p := gluVector3f(0, 0, 0);
333     result.v := fPosition * p;
334   end;
335   result := gluRayNormalize(result);
336 end;
337
338 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
339 constructor TglcCamera.Create;
340 begin
341   inherited Create;
342   fPosition := gluMatrixIdentity;
343 end;
344
345 end.
346