]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/clouds3d/camera.cpp
Tweak lib name.
[simgear.git] / simgear / scene / sky / clouds3d / camera.cpp
1 //------------------------------------------------------------------------------
2 // File : camera.cpp
3 //------------------------------------------------------------------------------
4 // GLVU : Copyright 1997 - 2002 
5 //        The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its 
8 // documentation for any purpose is hereby granted without fee, provided that 
9 // the above copyright notice appear in all copies and that both that copyright 
10 // notice and this permission notice appear in supporting documentation. 
11 // Binaries may be compiled with this software without any royalties or 
12 // restrictions. 
13 //
14 // The University of North Carolina at Chapel Hill makes no representations 
15 // about the suitability of this software for any purpose. It is provided 
16 // "as is" without express or implied warranty.
17
18 //============================================================================
19 // camera.cpp : camera class implementation
20 //----------------------------------------------------------------------------
21 // $Id$
22 //============================================================================
23 #include "camera.hpp"
24 #include <iostream.h>
25
26 //----------------------------------------------------------------------------
27 // CONSTRUCTOR: defines a default camera system defined as (45 DEG FOV)
28 //----------------------------------------------------------------------------
29 Camera::Camera()
30 {
31   X.Set(1,0,0); Y.Set(0,1,0); Z.Set(0,0,1);
32   Orig.Set(0,0,0);
33   Near=0.5f; Far=140.0f; wL=-1; wR=1; wT=1; wB=-1;
34  
35 }
36
37 Camera::Camera(const Camera &Cam)
38 {
39   Copy(Cam);
40 }
41
42 void Camera::Copy(const Camera &Cam)
43 {
44   X=Cam.X;  Y=Cam.Y;  Z=Cam.Z;  Orig=Cam.Orig;
45   Near=Cam.Near;  Far=Cam.Far;
46   wL=Cam.wL;  wR=Cam.wR;  wT=Cam.wT;  wB=Cam.wB;
47 }
48
49 //----------------------------------------------------------------------------
50 // OpenGL CAMERA ORIENTATION ROUTINE (glLookAt)
51 //----------------------------------------------------------------------------
52 void Camera::LookAt(
53   const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp)
54 {
55   Z = Eye-ViewRefPt;  Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
56   X = ViewUp/Z;       X.Normalize();
57   Y = Z/X;            Y.Normalize();
58   Orig = Eye;
59 }
60
61 //----------------------------------------------------------------------------
62 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (gluPerspective)
63 // Aspect = Width/Height; Yfov in degrees
64 //----------------------------------------------------------------------------
65 void Camera::Perspective(float Yfov, float Aspect, float Ndist, float Fdist)
66 {
67   Yfov *= 0.0174532f;  // CONVERT TO RADIANS
68   Near=Ndist;  Far=Fdist;
69   wT=(float)tan(Yfov*0.5f)*Near;  wB=-wT;
70   wR=wT*Aspect; wL=-wR;
71 }
72
73 //----------------------------------------------------------------------------
74 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (glFrustum). Window extents
75 // are defined on the viewplane at z=-Ndist.
76 //----------------------------------------------------------------------------
77 void Camera::Frustum(float l, float r, float b, float t, float Ndist, float Fdist)
78 {
79   Near=Ndist;  Far=Fdist;
80   wR=r;  wL=l;  wB=b;  wT=t;
81 }
82
83 //----------------------------------------------------------------------------
84 // Completely defines a camera as a tight fitting frustum surrounding the
85 // given bounding sphere. This is useful when most precision
86 // is required in pixel and depth resolution (for example, shadow-maps).
87 // The resulting camera is not skewed!
88 //----------------------------------------------------------------------------
89 void Camera::TightlyFitToSphere(
90   const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad)
91 {
92   // FIRST DEFINE COORDINATE FRAME
93   LookAt(Eye,Cntr,ViewUp);
94
95   // PROJECTED DIST TO CNTR ALONG VIEWDIR
96   float DistToCntr = (Cntr-Orig) * ViewDir();
97
98   // CALC TIGHT-FITTING NEAR AND FAR PLANES
99   Near = DistToCntr-Rad;
100   Far = DistToCntr+Rad;
101
102   //x = n*R / sqrt(d2 - r2)
103
104   if (Near<=0 || Far<=0) 
105     printf("ERROR (Camera::TightlyFitToSphere) Eye is inside the sphere!\n");
106
107   // CALC TIGHT-FITTING SIDES
108   wT = (Near * Rad) / (float)sqrt(DistToCntr*DistToCntr - Rad*Rad);//(Near * Rad) / DistToCntr;
109   wB = -wT;
110   wL = wB;
111   wR = wT;
112 }
113
114 //----------------------------------------------------------------------------
115 // Routines to return the Lookat, Perspective, and Frustum params.
116 // NOTE: Perspective is designed for non-skewed cameras: the viewing
117 //       direction must be centered on the viewplane window. Use frustum
118 //       for off-axis cameras.
119 //----------------------------------------------------------------------------
120 void Camera::GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const
121 {
122   *Eye = Orig;
123   *ViewRefPt = Orig - Z;
124   *ViewUp = Y;
125 }
126
127 void Camera::GetPerspectiveParams(float *Yfov, float *Aspect, 
128                                   float *Ndist, float *Fdist) const
129 {
130   *Yfov = (float)atan(wT/Near) * 57.29578f * 2.0f;  // CONVERT TO DEGREES
131   *Aspect = wR/wT;
132   *Ndist = Near;
133   *Fdist = Far;
134 }
135
136 void Camera::GetFrustumParams(float *l, float *r, float *b, float *t, 
137                               float *Ndist, float *Fdist) const
138 {
139   *l = wL;
140   *r = wR;
141   *b = wB;
142   *t = wT;
143   *Ndist = Near;
144   *Fdist = Far;
145 }
146
147 //----------------------------------------------------------------------------
148 // RETURNS THE COP OR EYE IN WORLD COORDS (ORIG OF CAMERA SYSTEM)
149 //----------------------------------------------------------------------------
150 const Vec3f& Camera::wCOP() const
151 {
152    return( Orig );
153 }
154
155 //----------------------------------------------------------------------------
156 // RETURNS THE VIEWING DIRECTION
157 //----------------------------------------------------------------------------
158 Vec3f Camera::ViewDir() const
159 {
160    return( -Z );
161 }
162
163 Vec3f Camera::ViewDirOffAxis() const
164 {
165   float x=(wL+wR)*0.5f, y=(wT+wB)*0.5f;  // MIDPOINT ON VIEWPLANE WINDOW
166   Vec3f ViewDir = X*x + Y*y - Z*Near;
167   ViewDir.Normalize();
168   return( ViewDir );
169 }
170
171 //----------------------------------------------------------------------------
172 // Vec3f WORLD-TO-CAM AND CAM-TO-WORLD ROUTINES
173 //----------------------------------------------------------------------------
174 Vec3f Camera::WorldToCam(const Vec3f& wP) const
175 {
176   Vec3f sP(wP-Orig);
177   Vec3f cP(X*sP,Y*sP,Z*sP);  return(cP);
178 }
179
180 // Return the z-value of the world point in camera space
181 float Camera::WorldToCamZ(const Vec3f& wP) const
182 {
183   Vec3f sP(wP-Orig);
184   float zdist = Z*sP;
185   return(zdist);
186 }
187
188
189 Vec3f Camera::CamToWorld(const Vec3f& cP) const
190 {
191   Vec3f wP(X*cP.x + Y*cP.y + Z*cP.z + Orig);  return(wP);
192 }
193
194 //----------------------------------------------------------------------------
195 // Makes the camera pose be the identity. World and camera space will be the
196 // same. Window extents and near/far planes are unaffected.
197 //----------------------------------------------------------------------------
198 void Camera::LoadIdentityXform()
199 {
200   X.Set(1,0,0);
201   Y.Set(0,1,0);
202   Z.Set(0,0,1);
203   Orig.Set(0,0,0);
204 }
205
206 //----------------------------------------------------------------------------
207 // Applies an OpenGL style premult/col vector xform to the coordinate frame.
208 // Only rotates, translates, and uniform scales are allowed.
209 // Window extents and near/far planes are affected by scaling.
210 //----------------------------------------------------------------------------
211 void Camera::Xform(const float M[16])
212 {
213   X.Set( X.x*M[0] + X.y*M[4] + X.z*M[8],
214          X.x*M[1] + X.y*M[5] + X.z*M[9],
215          X.x*M[2] + X.y*M[6] + X.z*M[10] );
216   Y.Set( Y.x*M[0] + Y.y*M[4] + Y.z*M[8],
217          Y.x*M[1] + Y.y*M[5] + Y.z*M[9],
218          Y.x*M[2] + Y.y*M[6] + Y.z*M[10] );
219   Z.Set( Z.x*M[0] + Z.y*M[4] + Z.z*M[8],
220          Z.x*M[1] + Z.y*M[5] + Z.z*M[9],
221          Z.x*M[2] + Z.y*M[6] + Z.z*M[10] );
222   Orig.Set( Orig.x*M[0] + Orig.y*M[4] + Orig.z*M[8] + M[12],
223             Orig.x*M[1] + Orig.y*M[5] + Orig.z*M[9] + M[13],
224             Orig.x*M[2] + Orig.y*M[6] + Orig.z*M[10] + M[14] );
225
226   // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
227   float Scale = X.Length();
228   X /= Scale;
229   Y /= Scale;
230   Z /= Scale;
231
232   // SCALE THE WINDOW EXTENTS AND THE NEAR/FAR PLANES
233   wL*=Scale;
234   wR*=Scale;
235   wB*=Scale;
236   wT*=Scale;
237   Near*=Scale;
238   Far*=Scale;
239 };
240
241
242 //----------------------------------------------------------------------------
243 // Translates the camera by the vector amount trans.
244 //----------------------------------------------------------------------------
245 void Camera::Translate(const Vec3f& trans)
246 {
247   Orig += trans;
248 }
249
250
251 //----------------------------------------------------------------------------
252 // Translates the camera about its origin by the rotation matrix M.
253 //----------------------------------------------------------------------------
254 void Camera::Rotate(const float M[9])
255 {
256   X.Set( X.x*M[0] + X.y*M[3] + X.z*M[6],
257          X.x*M[1] + X.y*M[4] + X.z*M[7],
258          X.x*M[2] + X.y*M[5] + X.z*M[8] );
259   Y.Set( Y.x*M[0] + Y.y*M[3] + Y.z*M[6],
260          Y.x*M[1] + Y.y*M[4] + Y.z*M[7],
261          Y.x*M[2] + Y.y*M[5] + Y.z*M[8] );
262   Z.Set( Z.x*M[0] + Z.y*M[3] + Z.z*M[6],
263          Z.x*M[1] + Z.y*M[4] + Z.z*M[7],
264          Z.x*M[2] + Z.y*M[5] + Z.z*M[8] );
265 }
266
267
268 //----------------------------------------------------------------------------
269 // Returns the COMPOSITE xform matrix that takes a point in the object space
270 // to a screen space (pixel) point. The inverse is also provided.
271 // You have to give the pixel dimensions of the viewport window.
272 //----------------------------------------------------------------------------
273 float* Camera::GetXform_Screen2Obj(float* M, int WW, int WH) const
274 {
275   Screen2WorldXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
276                         wL,wR,wB,wT,Near,Far,WW,WH);
277   return(M);
278 }
279
280 float* Camera::GetXform_Obj2Screen(float* M, int WW, int WH) const
281 {
282   World2ScreenXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
283                         wL,wR,wB,wT,Near,Far,WW,WH);
284   return(M);
285 }
286
287 //----------------------------------------------------------------------------
288 // OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/COL VECT, 4x4 MATRIX)
289 // A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
290 // VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
291 // WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
292 // Modelview XFORM. The associated inverse matrices are also provided.
293 //----------------------------------------------------------------------------
294 float* Camera::GetModelviewMatrix(float* M) const
295 {
296   Viewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
297   return(M);
298 }
299
300 float* Camera::GetInvModelviewMatrix(float* M) const
301 {  
302   invViewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
303   return(M);
304 }
305
306 float* Camera::GetProjectionMatrix(float* M) const
307 {
308   Frustum16fv(M,wL,wR,wB,wT,Near,Far);
309   return(M);  
310 }
311
312 void Camera::SetModelviewMatrix(const float* M)
313 {
314   Viewing2CoordFrame16fv(M, &(X.x), &(Y.x), &(Z.x), &(Orig.x));
315 }
316
317 float* Camera::GetInvProjectionMatrix(float* M) const
318 {
319   invFrustum16fv(M,wL,wR,wB,wT,Near,Far);
320   return(M);  
321 }
322
323 float* Camera::GetViewportMatrix(float* M, int WW, int WH) const
324 {
325   Viewport16fv(M,WW,WH);
326   return(M);
327 }
328
329 float* Camera::GetInvViewportMatrix(float* M, int WW, int WH) const
330 {
331   invViewport16fv(M,WW,WH);
332   return(M);
333 }
334
335 //----------------------------------------------------------------------------
336 // Given a screen pixel location (sx,sy) w/ (0,0) at the lower-left and the
337 // screen dimensions, return the ray (start,dir) of the ray in world coords.
338 //----------------------------------------------------------------------------
339 void Camera::GetPixelRay(float sx, float sy, int ww, int wh, 
340                          Vec3f *Start, Vec3f *Dir) const
341 {
342   Vec3f wTL = Orig + (X*wL) + (Y*wT) - (Z*Near);  // FIND LOWER-LEFT
343   Vec3f dX = (X*(wR-wL))/(float)ww;               // WORLD WIDTH OF PIXEL
344   Vec3f dY = (Y*(wT-wB))/(float)wh;               // WORLD HEIGHT OF PIXEL
345   wTL += (dX*sx - dY*sy);                         // INCR TO WORLD PIXEL
346   wTL += (dX*0.5 - dY*0.5);                       // INCR TO PIXEL CNTR
347   *Start = Orig;
348   *Dir = wTL-Orig;
349 }
350
351 //----------------------------------------------------------------------------
352 // READ AND WRITE CAMERA AXES AND ORIGIN TO AND FROM A FILE GIVEN A FILE PTR.
353 //----------------------------------------------------------------------------
354 void Camera::WriteToFile(FILE *fp) const
355 {
356  if (fp==NULL) { printf("ERROR WRITING CAM TO FILE!\n"); return; }
357  fprintf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f\n",
358   X.x,X.y,X.z, Y.x,Y.y,Y.z, Z.x,Z.y,Z.z, Orig.x,Orig.y,Orig.z);
359 }
360
361 int Camera::ReadFromFile(FILE *fp)  // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
362 {
363  int Cond = fscanf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f",
364                    &X.x,&X.y,&X.z, &Y.x,&Y.y,&Y.z, 
365                    &Z.x,&Z.y,&Z.z, &Orig.x,&Orig.y,&Orig.z);
366  return(Cond!=EOF);
367 }
368
369 //----------------------------------------------------------------------------
370 // 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
371 // (Left,Right, Bottom,Top, Near,Far)
372 // In order, near pts counter-clockwise starting with right-top-near (RTN) pt
373 // and then far pts ccw starting with right-top-far (RTF) pt
374 //----------------------------------------------------------------------------
375 void Camera::CalcVerts(Vec3f *V)  const // MUST BE PREALLOCED : "Vec3f V[8]"
376 {
377   // WINDOW EXTENTS ARE DEFINED ON THE NEAR PLANE, CALC NEAR PTS (IN CAM COORDS)
378   float NearZ = -Near;
379   V[0].Set(wR,wT,NearZ);
380   V[1].Set(wL,wT,NearZ);
381   V[2].Set(wL,wB,NearZ);
382   V[3].Set(wR,wB,NearZ);
383
384   // CALC FAR PTS (IN CAM COORDS)
385   float FarZ=-Far, FN=Far/Near;
386   float fwL=wL*FN, fwR=wR*FN, fwB=wB*FN, fwT=wT*FN;
387   V[4].Set(fwR,fwT,FarZ);
388   V[5].Set(fwL,fwT,FarZ);
389   V[6].Set(fwL,fwB,FarZ);
390   V[7].Set(fwR,fwB,FarZ);
391
392   // XFORM FRUSTUM IN CAM COORDS TO WORLD SPACE
393   for (int i=0; i<8; i++)
394     V[i] = CamToWorld(V[i]); 
395 }
396
397 //----------------------------------------------------------------------------
398 // PRINT ROUTINE
399 //----------------------------------------------------------------------------
400 void Camera::Print() const
401 {
402   printf("Camera System Parameters:\n");
403   printf("       X: (%.3f, %.3f, %.3f)\n", X.x, X.y, X.z);
404   printf("       Y: (%.3f, %.3f, %.3f)\n", Y.x, Y.y, Y.z);
405   printf("       Z: (%.3f, %.3f, %.3f)\n", Z.x, Z.y, Z.z);
406   printf("  Origin: (%.3f, %.3f, %.3f)\n", Orig.x, Orig.y, Orig.z);
407   printf(" NFLRBT: (%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
408                Near,Far,wL,wR,wB,wT);
409 };