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