]> git.mxchange.org Git - flightgear.git/blob - Simulator/Main/views.cxx
Merge Include as subdirectory
[flightgear.git] / Simulator / Main / views.cxx
1 // views.cxx -- data structures and routines for managing and view
2 //               parameters.
3 //
4 // Written by Curtis Olson, started August 1997.
5 //
6 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23 // (Log is kept at end of this file)
24
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #include <Aircraft/aircraft.hxx>
31 #include <Cockpit/panel.hxx>
32 #include <Debug/logstream.hxx>
33 #include <Include/fg_constants.h>
34 #include <Math/mat3.h>
35 #include <Math/point3d.hxx>
36 #include <Math/polar3d.hxx>
37 #include <Math/vector.hxx>
38 #include <Scenery/scenery.hxx>
39 #include <Time/fg_time.hxx>
40
41 #include "options.hxx"
42 #include "views.hxx"
43
44
45 // Define following to extract various vectors directly
46 // from matrices we have allready computed
47 // rather then performing 'textbook algebra' to rederive them
48 // Norman Vine -- nhv@yahoo.com
49 // #define FG_VIEW_INLINE_OPTIMIZATIONS
50
51 // temporary (hopefully) hack
52 static int panel_hist = 0;
53
54
55 // specify code paths ... these are done as variable rather than
56 // #define's because down the road we may want to choose between them
57 // on the fly for different flight models ... this way magic carpet
58 // and external modes wouldn't need to recreate the LaRCsim matrices
59 // themselves.
60
61 static const bool use_larcsim_local_to_body = false;
62
63
64 // This is a record containing current view parameters
65 FGView current_view;
66
67
68 // Constructor
69 FGView::FGView( void ) {
70     MAT3identity(WORLD);
71 }
72
73
74 // Initialize a view structure
75 void FGView::Init( void ) {
76     FG_LOG( FG_VIEW, FG_INFO, "Initializing View parameters" );
77
78     view_offset = 0.0;
79     goal_view_offset = 0.0;
80
81     winWidth = current_options.get_xsize();
82     winHeight = current_options.get_ysize();
83
84     if ( ! current_options.get_panel_status() ) {
85         current_view.set_win_ratio( (GLfloat) winWidth / (GLfloat) winHeight );
86     } else {
87         current_view.set_win_ratio( (GLfloat) winWidth / 
88                                     ((GLfloat) (winHeight)*0.4232) );
89     }
90
91     force_update_fov_math();
92 }
93
94
95 // Update the field of view coefficients
96 void FGView::UpdateFOV( const fgOPTIONS& o ) {
97     double fov, theta_x, theta_y;
98
99     fov = o.get_fov();
100         
101     // printf("win_ratio = %.2f\n", win_ratio);
102     // calculate sin() and cos() of fov / 2 in X direction;
103     theta_x = (fov * win_ratio * DEG_TO_RAD) / 2.0;
104     // printf("theta_x = %.2f\n", theta_x);
105     sin_fov_x = sin(theta_x);
106     cos_fov_x = cos(theta_x);
107     slope_x =  -cos_fov_x / sin_fov_x;
108     // printf("slope_x = %.2f\n", slope_x);
109
110     // fov_x_clip and fov_y_clip convoluted algebraic simplification
111     // see code executed in tilemgr.cxx when USE_FAST_FOV_CLIP not
112     // defined Norman Vine -- nhv@yahoo.com
113 #if defined( USE_FAST_FOV_CLIP )
114     fov_x_clip = slope_x*cos_fov_x - sin_fov_x;
115 #endif // defined( USE_FAST_FOV_CLIP )
116
117     // calculate sin() and cos() of fov / 2 in Y direction;
118     theta_y = (fov * DEG_TO_RAD) / 2.0;
119     // printf("theta_y = %.2f\n", theta_y);
120     sin_fov_y = sin(theta_y);
121     cos_fov_y = cos(theta_y);
122     slope_y = cos_fov_y / sin_fov_y;
123     // printf("slope_y = %.2f\n", slope_y);
124
125 #if defined( USE_FAST_FOV_CLIP )
126     fov_y_clip = -(slope_y*cos_fov_y + sin_fov_y);      
127 #endif // defined( USE_FAST_FOV_CLIP )
128 }
129
130
131 // Basically, this is a modified version of the Mesa gluLookAt()
132 // function that's been modified slightly so we can capture the
133 // result before sending it off to OpenGL land.
134 void FGView::LookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
135                      GLdouble centerx, GLdouble centery, GLdouble centerz,
136                      GLdouble upx, GLdouble upy, GLdouble upz ) {
137     GLdouble *m;
138     GLdouble x[3], y[3], z[3];
139     GLdouble mag;
140
141     m = current_view.MODEL_VIEW;
142
143     /* Make rotation matrix */
144
145     /* Z vector */
146     z[0] = eyex - centerx;
147     z[1] = eyey - centery;
148     z[2] = eyez - centerz;
149     mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
150     if (mag) {  /* mpichler, 19950515 */
151         z[0] /= mag;
152         z[1] /= mag;
153         z[2] /= mag;
154     }
155
156     /* Y vector */
157     y[0] = upx;
158     y[1] = upy;
159     y[2] = upz;
160
161     /* X vector = Y cross Z */
162     x[0] =  y[1]*z[2] - y[2]*z[1];
163     x[1] = -y[0]*z[2] + y[2]*z[0];
164     x[2] =  y[0]*z[1] - y[1]*z[0];
165     
166     /* Recompute Y = Z cross X */
167     y[0] =  z[1]*x[2] - z[2]*x[1];
168     y[1] = -z[0]*x[2] + z[2]*x[0];
169     y[2] =  z[0]*x[1] - z[1]*x[0];
170
171     /* mpichler, 19950515 */
172     /* cross product gives area of parallelogram, which is < 1.0 for
173      * non-perpendicular unit-length vectors; so normalize x, y here
174      */
175
176     mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
177     if (mag) {
178         x[0] /= mag;
179         x[1] /= mag;
180         x[2] /= mag;
181     }
182
183     mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
184     if (mag) {
185         y[0] /= mag;
186         y[1] /= mag;
187         y[2] /= mag;
188     }
189
190 #define M(row,col)  m[col*4+row]
191     M(0,0) = x[0];  M(0,1) = x[1];  M(0,2) = x[2];  M(0,3) = 0.0;
192     M(1,0) = y[0];  M(1,1) = y[1];  M(1,2) = y[2];  M(1,3) = 0.0;
193     M(2,0) = z[0];  M(2,1) = z[1];  M(2,2) = z[2];  M(2,3) = 0.0;
194     // the following is part of the original gluLookAt(), but we are
195     // commenting it out because we know we are going to be doing a
196     // translation below which will set these values anyways
197     // M(3,0) = 0.0;   M(3,1) = 0.0;   M(3,2) = 0.0;   M(3,3) = 1.0;
198 #undef M
199
200     // Translate Eye to Origin
201     // replaces: glTranslated( -eyex, -eyey, -eyez );
202
203     // this has been slightly modified from the original glTranslate()
204     // code because we know that coming into this m[12] = m[13] =
205     // m[14] = 0.0, and m[15] = 1.0;
206     m[12] = m[0] * -eyex + m[4] * -eyey + m[8]  * -eyez /* + m[12] */;
207     m[13] = m[1] * -eyex + m[5] * -eyey + m[9]  * -eyez /* + m[13] */;
208     m[14] = m[2] * -eyex + m[6] * -eyey + m[10] * -eyez /* + m[14] */;
209     m[15] = 1.0 /* m[3] * -eyex + m[7] * -eyey + m[11] * -eyez + m[15] */;
210
211     // xglMultMatrixd( m );
212     xglLoadMatrixd( m );
213 }
214
215
216 // Update the view volume, position, and orientation
217 void FGView::UpdateViewParams( void ) {
218     FGInterface *f = current_aircraft.fdm_state;
219
220     UpdateViewMath(f);
221     UpdateWorldToEye(f);
222     
223     if ((current_options.get_panel_status() != panel_hist) &&                          (current_options.get_panel_status()))
224     {
225         FGPanel::OurPanel->ReInit( 0, 0, 1024, 768);
226     }
227
228     if ( ! current_options.get_panel_status() ) {
229         xglViewport(0, 0 , (GLint)(winWidth), (GLint)(winHeight) );
230     } else {
231         xglViewport(0, (GLint)((winHeight)*0.5768), (GLint)(winWidth), 
232                     (GLint)((winHeight)*0.4232) );
233     }
234
235     // Tell GL we are about to modify the projection parameters
236     xglMatrixMode(GL_PROJECTION);
237     xglLoadIdentity();
238     if ( f->get_Altitude() * FEET_TO_METER - scenery.cur_elev > 10.0 ) {
239         gluPerspective(current_options.get_fov(), win_ratio, 10.0, 100000.0);
240     } else {
241         gluPerspective(current_options.get_fov(), win_ratio, 0.5, 100000.0);
242         // printf("Near ground, minimizing near clip plane\n");
243     }
244     // }
245
246     xglMatrixMode(GL_MODELVIEW);
247     xglLoadIdentity();
248     
249     // set up our view volume (default)
250 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
251     LookAt(view_pos.x(), view_pos.y(), view_pos.z(),
252            view_pos.x() + view_forward[0], 
253            view_pos.y() + view_forward[1], 
254            view_pos.z() + view_forward[2],
255            view_up[0], view_up[1], view_up[2]);
256
257     // look almost straight up (testing and eclipse watching)
258     /* LookAt(view_pos.x(), view_pos.y(), view_pos.z(),
259        view_pos.x() + view_up[0] + .001, 
260        view_pos.y() + view_up[1] + .001, 
261        view_pos.z() + view_up[2] + .001,
262        view_up[0], view_up[1], view_up[2]); */
263
264     // lock view horizontally towards sun (testing)
265     /* LookAt(view_pos.x(), view_pos.y(), view_pos.z(),
266        view_pos.x() + surface_to_sun[0], 
267        view_pos.y() + surface_to_sun[1], 
268        view_pos.z() + surface_to_sun[2],
269        view_up[0], view_up[1], view_up[2]); */
270
271     // lock view horizontally towards south (testing)
272     /* LookAt(view_pos.x(), view_pos.y(), view_pos.z(),
273        view_pos.x() + surface_south[0], 
274        view_pos.y() + surface_south[1], 
275        view_pos.z() + surface_south[2],
276        view_up[0], view_up[1], view_up[2]); */
277
278 #else // defined(FG_VIEW_INLINE_OPTIMIZATIONS)
279     //void FGView::LookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez,
280     //               GLdouble centerx, GLdouble centery, GLdouble centerz,
281     //               GLdouble upx, GLdouble upy, GLdouble upz )
282     {
283         GLdouble *m;
284         GLdouble x[3], y[3], z[3];
285         //    GLdouble mag;
286
287         m = current_view.MODEL_VIEW;
288
289         /* Make rotation matrix */
290
291         /* Z vector */
292         z[0] = -view_forward[0]; //eyex - centerx;
293         z[1] = -view_forward[1]; //eyey - centery;
294         z[2] = -view_forward[2]; //eyez - centerz;
295         
296         // In our case this is a unit vector  NHV
297         
298         //    mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] );
299         //    if (mag) {  /* mpichler, 19950515 */
300         //              mag = 1.0/mag;
301         //              printf("mag(%f)  ", mag);
302         //      z[0] *= mag;
303         //      z[1] *= mag;
304         //      z[2] *= mag;
305         //    }
306
307         /* Y vector */
308         y[0] = view_up[0]; //upx;
309         y[1] = view_up[1]; //upy;
310         y[2] = view_up[2]; //upz;
311
312         /* X vector = Y cross Z */
313         x[0] =  y[1]*z[2] - y[2]*z[1];
314         x[1] = -y[0]*z[2] + y[2]*z[0];
315         x[2] =  y[0]*z[1] - y[1]*z[0];
316
317         //      printf(" %f %f %f  ", y[0], y[1], y[2]);
318     
319         /* Recompute Y = Z cross X */
320         //    y[0] =  z[1]*x[2] - z[2]*x[1];
321         //    y[1] = -z[0]*x[2] + z[2]*x[0];
322         //    y[2] =  z[0]*x[1] - z[1]*x[0];
323
324         //      printf(" %f %f %f\n", y[0], y[1], y[2]);
325         
326         // In our case these are unit vectors  NHV
327
328         /* mpichler, 19950515 */
329         /* cross product gives area of parallelogram, which is < 1.0 for
330          * non-perpendicular unit-length vectors; so normalize x, y here
331          */
332
333         //    mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
334         //    if (mag) {
335         //              mag = 1.0/mag;
336         //              printf("mag2(%f) ", mag);
337         //      x[0] *= mag;
338         //      x[1] *= mag;
339         //      x[2] *= mag;
340         //    }
341
342         //    mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] );
343         //    if (mag) {
344         //              mag = 1.0/mag;
345         //              printf("mag3(%f)\n", mag);
346         //      y[0] *= mag;
347         //      y[1] *= mag;
348         //      y[2] *= mag;
349         //    }
350
351 #define M(row,col)  m[col*4+row]
352         M(0,0) = x[0];  M(0,1) = x[1];  M(0,2) = x[2];  M(0,3) = 0.0;
353         M(1,0) = y[0];  M(1,1) = y[1];  M(1,2) = y[2];  M(1,3) = 0.0;
354         M(2,0) = z[0];  M(2,1) = z[1];  M(2,2) = z[2];  M(2,3) = 0.0;
355         // the following is part of the original gluLookAt(), but we are
356         // commenting it out because we know we are going to be doing a
357         // translation below which will set these values anyways
358         // M(3,0) = 0.0;   M(3,1) = 0.0;   M(3,2) = 0.0;   M(3,3) = 1.0;
359 #undef M
360
361         // Translate Eye to Origin
362         // replaces: glTranslated( -eyex, -eyey, -eyez );
363
364         // this has been slightly modified from the original glTranslate()
365         // code because we know that coming into this m[12] = m[13] =
366         // m[14] = 0.0, and m[15] = 1.0;
367         m[12] = m[0] * -view_pos.x() + m[4] * -view_pos.y() + m[8]  * -view_pos.z() /* + m[12] */;
368         m[13] = m[1] * -view_pos.x() + m[5] * -view_pos.y() + m[9]  * -view_pos.z() /* + m[13] */;
369         m[14] = m[2] * -view_pos.x() + m[6] * -view_pos.y() + m[10] * -view_pos.z() /* + m[14] */;
370         m[15] = 1.0 /* m[3] * -view_pos.x() + m[7] * -view_pos.y() + m[11] * -view_pos.z() + m[15] */;
371
372         // xglMultMatrixd( m );
373         xglLoadMatrixd( m );
374     }
375 #endif // FG_VIEW_INLINE_OPTIMIZATIONS
376         
377
378     panel_hist = current_options.get_panel_status();
379 }
380
381
382 void getRotMatrix(double* out, MAT3vec vec, double radians)
383 {
384     /* This function contributed by Erich Boleyn (erich@uruk.org) */
385     /* This function used from the Mesa OpenGL code (matrix.c)  */
386     double s, c; // mag,
387     double vx, vy, vz, xy, yz, zx, xs, ys, zs, one_c; //, xx, yy, zz
388   
389     MAT3identity(out);
390     s = sin(radians);
391     c = cos(radians);
392   
393     //  mag = getMagnitude();
394   
395     vx = vec[0];
396     vy = vec[1];
397     vz = vec[2];
398   
399 #define M(row,col)  out[row*4 + col]
400   
401     /*
402      *     Arbitrary axis rotation matrix.
403      *
404      *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
405      *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
406      *  (which is about the X-axis), and the two composite transforms
407      *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
408      *  from the arbitrary axis to the X-axis then back.  They are
409      *  all elementary rotations.
410      *
411      *  Rz' is a rotation about the Z-axis, to bring the axis vector
412      *  into the x-z plane.  Then Ry' is applied, rotating about the
413      *  Y-axis to bring the axis vector parallel with the X-axis.  The
414      *  rotation about the X-axis is then performed.  Ry and Rz are
415      *  simply the respective inverse transforms to bring the arbitrary
416      *  axis back to it's original orientation.  The first transforms
417      *  Rz' and Ry' are considered inverses, since the data from the
418      *  arbitrary axis gives you info on how to get to it, not how
419      *  to get away from it, and an inverse must be applied.
420      *
421      *  The basic calculation used is to recognize that the arbitrary
422      *  axis vector (x, y, z), since it is of unit length, actually
423      *  represents the sines and cosines of the angles to rotate the
424      *  X-axis to the same orientation, with theta being the angle about
425      *  Z and phi the angle about Y (in the order described above)
426      *  as follows:
427      *
428      *  cos ( theta ) = x / sqrt ( 1 - z^2 )
429      *  sin ( theta ) = y / sqrt ( 1 - z^2 )
430      *
431      *  cos ( phi ) = sqrt ( 1 - z^2 )
432      *  sin ( phi ) = z
433      *
434      *  Note that cos ( phi ) can further be inserted to the above
435      *  formulas:
436      *
437      *  cos ( theta ) = x / cos ( phi )
438      *  sin ( theta ) = y / cos ( phi )
439      *
440      *  ...etc.  Because of those relations and the standard trigonometric
441      *  relations, it is pssible to reduce the transforms down to what
442      *  is used below.  It may be that any primary axis chosen will give the
443      *  same results (modulo a sign convention) using thie method.
444      *
445      *  Particularly nice is to notice that all divisions that might
446      *  have caused trouble when parallel to certain planes or
447      *  axis go away with care paid to reducing the expressions.
448      *  After checking, it does perform correctly under all cases, since
449      *  in all the cases of division where the denominator would have
450      *  been zero, the numerator would have been zero as well, giving
451      *  the expected result.
452      */
453     
454     one_c = 1.0F - c;
455     
456     //  xx = vx * vx;
457     //  yy = vy * vy;
458     //  zz = vz * vz;
459   
460     //  xy = vx * vy;
461     //  yz = vy * vz;
462     //  zx = vz * vx;
463   
464   
465     M(0,0) = (one_c * vx * vx) + c;  
466     xs = vx * s;
467     yz = vy * vz * one_c;
468     M(1,2) = yz + xs;
469     M(2,1) = yz - xs;
470
471     M(1,1) = (one_c * vy * vy) + c;
472     ys = vy * s;
473     zx = vz * vx * one_c;
474     M(0,2) = zx - ys;
475     M(2,0) = zx + ys;
476   
477     M(2,2) = (one_c * vz *vz) + c;
478     zs = vz * s;
479     xy = vx * vy * one_c;
480     M(0,1) = xy + zs;
481     M(1,0) = xy - zs;
482   
483     //  M(0,0) = (one_c * xx) + c;
484     //  M(1,0) = (one_c * xy) - zs;
485     //  M(2,0) = (one_c * zx) + ys;
486   
487     //  M(0,1) = (one_c * xy) + zs;
488     //  M(1,1) = (one_c * yy) + c;
489     //  M(2,1) = (one_c * yz) - xs;
490   
491     //  M(0,2) = (one_c * zx) - ys;
492     //  M(1,2) = (one_c * yz) + xs;
493     //  M(2,2) = (one_c * zz) + c;
494   
495 #undef M
496 }
497
498
499 // Update the view parameters
500 void FGView::UpdateViewMath( FGInterface *f ) {
501     Point3D p;
502     MAT3vec vec, forward, v0, minus_z;
503     MAT3mat R, TMP, UP, LOCAL, VIEW;
504     double ntmp;
505
506     if ( update_fov ) {
507         // printf("Updating fov\n");
508         UpdateFOV( current_options );
509         update_fov = false;
510     }
511                 
512     scenery.center = scenery.next_center;
513
514 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
515     // printf("scenery center = %.2f %.2f %.2f\n", scenery.center.x,
516     //        scenery.center.y, scenery.center.z);
517
518     // calculate the cartesion coords of the current lat/lon/0 elev
519     p = Point3D( f->get_Longitude(), 
520                  f->get_Lat_geocentric(), 
521                  f->get_Sea_level_radius() * FEET_TO_METER );
522
523     cur_zero_elev = fgPolarToCart3d(p) - scenery.center;
524
525     // calculate view position in current FG view coordinate system
526     // p.lon & p.lat are already defined earlier, p.radius was set to
527     // the sea level radius, so now we add in our altitude.
528     if ( f->get_Altitude() * FEET_TO_METER > 
529          (scenery.cur_elev + 0.5 * METER_TO_FEET) ) {
530         p.setz( p.radius() + f->get_Altitude() * FEET_TO_METER );
531     } else {
532         p.setz( p.radius() + scenery.cur_elev + 0.5 * METER_TO_FEET );
533     }
534
535     abs_view_pos = fgPolarToCart3d(p);
536         
537 #else // FG_VIEW_INLINE_OPTIMIZATIONS
538         
539     double tmp_radius = f->get_Sea_level_radius() * FEET_TO_METER;
540     double tmp = f->get_cos_lat_geocentric() * tmp_radius;
541         
542     cur_zero_elev.setx(f->get_cos_longitude()*tmp - scenery.center.x());
543     cur_zero_elev.sety(f->get_sin_longitude()*tmp - scenery.center.y());
544     cur_zero_elev.setz(f->get_sin_lat_geocentric()*tmp_radius - scenery.center.z());
545
546     // calculate view position in current FG view coordinate system
547     // p.lon & p.lat are already defined earlier, p.radius was set to
548     // the sea level radius, so now we add in our altitude.
549     if ( f->get_Altitude() * FEET_TO_METER > 
550          (scenery.cur_elev + 0.5 * METER_TO_FEET) ) {
551         tmp_radius += f->get_Altitude() * FEET_TO_METER;
552     } else {
553         tmp_radius += scenery.cur_elev + 0.5 * METER_TO_FEET ;
554     }
555     tmp = f->get_cos_lat_geocentric() * tmp_radius;
556     abs_view_pos.setx(f->get_cos_longitude()*tmp);
557     abs_view_pos.sety(f->get_sin_longitude()*tmp);
558     abs_view_pos.setz(f->get_sin_lat_geocentric()*tmp_radius);
559         
560 #endif // FG_VIEW_INLINE_OPTIMIZATIONS
561         
562     view_pos = abs_view_pos - scenery.center;
563
564     FG_LOG( FG_VIEW, FG_DEBUG, "Polar view pos = " << p );
565     FG_LOG( FG_VIEW, FG_DEBUG, "Absolute view pos = " << abs_view_pos );
566     FG_LOG( FG_VIEW, FG_DEBUG, "Relative view pos = " << view_pos );
567
568     // Derive the LOCAL aircraft rotation matrix (roll, pitch, yaw)
569     // from FG_T_local_to_body[3][3]
570
571     if ( use_larcsim_local_to_body ) {
572
573         // Question: Why is the LaRCsim matrix arranged so differently
574         // than the one we need???
575
576         // Answer (I think): The LaRCsim matrix is generated in a
577         // different reference frame than we've set up for our world
578
579         LOCAL[0][0] = f->get_T_local_to_body_33();
580         LOCAL[0][1] = -f->get_T_local_to_body_32();
581         LOCAL[0][2] = -f->get_T_local_to_body_31();
582         LOCAL[0][3] = 0.0;
583         LOCAL[1][0] = -f->get_T_local_to_body_23();
584         LOCAL[1][1] = f->get_T_local_to_body_22();
585         LOCAL[1][2] = f->get_T_local_to_body_21();
586         LOCAL[1][3] = 0.0;
587         LOCAL[2][0] = -f->get_T_local_to_body_13();
588         LOCAL[2][1] = f->get_T_local_to_body_12();
589         LOCAL[2][2] = f->get_T_local_to_body_11();
590         LOCAL[2][3] = 0.0;
591         LOCAL[3][0] = LOCAL[3][1] = LOCAL[3][2] = LOCAL[3][3] = 0.0;
592         LOCAL[3][3] = 1.0;
593
594         // printf("LaRCsim LOCAL matrix\n");
595         // MAT3print(LOCAL, stdout);
596
597     } else {
598
599         // code to calculate LOCAL matrix calculated from Phi, Theta, and
600         // Psi (roll, pitch, yaw) in case we aren't running LaRCsim as our
601         // flight model
602
603         MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
604         MAT3rotate(R, vec, f->get_Phi());
605         /* printf("Roll matrix\n"); */
606         /* MAT3print(R, stdout); */
607
608         MAT3_SET_VEC(vec, 0.0, 1.0, 0.0);
609         /* MAT3mult_vec(vec, vec, R); */
610         MAT3rotate(TMP, vec, f->get_Theta());
611         /* printf("Pitch matrix\n"); */
612         /* MAT3print(TMP, stdout); */
613         MAT3mult(R, R, TMP);
614
615         MAT3_SET_VEC(vec, 1.0, 0.0, 0.0);
616         /* MAT3mult_vec(vec, vec, R); */
617         /* MAT3rotate(TMP, vec, FG_Psi - FG_PI_2); */
618         MAT3rotate(TMP, vec, -f->get_Psi());
619         /* printf("Yaw matrix\n");
620            MAT3print(TMP, stdout); */
621         MAT3mult(LOCAL, R, TMP);
622         // printf("FG derived LOCAL matrix\n");
623         // MAT3print(LOCAL, stdout);
624
625     } // if ( use_larcsim_local_to_body ) 
626
627 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
628         
629     // Derive the local UP transformation matrix based on *geodetic*
630     // coordinates
631     MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
632     MAT3rotate(R, vec, f->get_Longitude());     // R = rotate about Z axis
633     // printf("Longitude matrix\n");
634     // MAT3print(R, stdout);
635
636     MAT3_SET_VEC(vec, 0.0, 1.0, 0.0);
637     MAT3mult_vec(vec, vec, R);
638     MAT3rotate(TMP, vec, -f->get_Latitude());  // TMP = rotate about X axis
639     // printf("Latitude matrix\n");
640     // MAT3print(TMP, stdout);
641
642     MAT3mult(UP, R, TMP);
643     // printf("Local up matrix\n");
644     // MAT3print(UP, stdout);
645
646     MAT3_SET_VEC(local_up, 1.0, 0.0, 0.0);
647     MAT3mult_vec(local_up, local_up, UP);
648
649     // printf( "Local Up = (%.4f, %.4f, %.4f)\n",
650     //         local_up[0], local_up[1], local_up[2]);
651     
652     // Alternative method to Derive local up vector based on
653     // *geodetic* coordinates
654     // alt_up = fgPolarToCart(FG_Longitude, FG_Latitude, 1.0);
655     // printf( "    Alt Up = (%.4f, %.4f, %.4f)\n", 
656     //         alt_up.x, alt_up.y, alt_up.z);
657
658     // Calculate the VIEW matrix
659     MAT3mult(VIEW, LOCAL, UP);
660     // printf("VIEW matrix\n");
661     // MAT3print(VIEW, stdout);
662
663     // generate the current up, forward, and fwrd-view vectors
664     MAT3_SET_VEC(vec, 1.0, 0.0, 0.0);
665     MAT3mult_vec(view_up, vec, VIEW);
666
667     MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
668     MAT3mult_vec(forward, vec, VIEW);
669     // printf( "Forward vector is (%.2f,%.2f,%.2f)\n", forward[0], forward[1], 
670     //         forward[2]);
671
672     MAT3rotate(TMP, view_up, view_offset);
673     MAT3mult_vec(view_forward, forward, TMP);
674
675     // make a vector to the current view position
676     MAT3_SET_VEC(v0, view_pos.x(), view_pos.y(), view_pos.z());
677
678     // Given a vector pointing straight down (-Z), map into onto the
679     // local plane representing "horizontal".  This should give us the
680     // local direction for moving "south".
681     MAT3_SET_VEC(minus_z, 0.0, 0.0, -1.0);
682     map_vec_onto_cur_surface_plane(local_up, v0, minus_z, surface_south);
683     MAT3_NORMALIZE_VEC(surface_south, ntmp);
684     // printf( "Surface direction directly south %.2f %.2f %.2f\n",
685     //         surface_south[0], surface_south[1], surface_south[2]);
686
687     // now calculate the surface east vector
688     MAT3rotate(TMP, view_up, FG_PI_2);
689     MAT3mult_vec(surface_east, surface_south, TMP);
690     // printf( "Surface direction directly east %.2f %.2f %.2f\n",
691     //         surface_east[0], surface_east[1], surface_east[2]);
692     // printf( "Should be close to zero = %.2f\n", 
693     //         MAT3_DOT_PRODUCT(surface_south, surface_east));
694         
695 #else // FG_VIEW_INLINE_OPTIMIZATIONS
696          
697     //  // Build spherical to cartesian transform matrix directly
698     double cos_lat = f->get_cos_latitude(); // cos(-f->get_Latitude());
699     double sin_lat = -f->get_sin_latitude(); // sin(-f->get_Latitude());
700     double cos_lon = f->get_cos_longitude(); //cos(f->get_Longitude());
701     double sin_lon = f->get_sin_longitude(); //sin(f->get_Longitude());
702
703     double *mat = (double *)UP;
704         
705     mat[0] =  cos_lat*cos_lon;
706     mat[1] =  cos_lat*sin_lon;
707     mat[2] = -sin_lat;
708     mat[3] =  0.0;
709     mat[4] =  -sin_lon;
710     mat[5] =  cos_lon;
711     mat[6] =  0.0;
712     mat[7] =  0.0;
713     mat[8]  =  sin_lat*cos_lon;
714     mat[9]  =  sin_lat*sin_lon;
715     mat[10] =  cos_lat;
716     mat[11] =  mat[12] = mat[13] = mat[14] = 0.0;
717     mat[15] =  1.0;
718
719     MAT3mult(VIEW, LOCAL, UP);
720         
721     // THESE COULD JUST BE POINTERS !!!
722     MAT3_SET_VEC(local_up, mat[0],     mat[1],     mat[2]);
723     MAT3_SET_VEC(view_up,  VIEW[0][0], VIEW[0][1], VIEW[0][2]);
724     MAT3_SET_VEC(forward,  VIEW[2][0], VIEW[2][1], VIEW[2][2]);
725
726     getRotMatrix((double *)TMP, view_up, view_offset);
727     MAT3mult_vec(view_forward, forward, TMP);
728
729     // make a vector to the current view position
730     MAT3_SET_VEC(v0, view_pos.x(), view_pos.y(), view_pos.z());
731
732     // Given a vector pointing straight down (-Z), map into onto the
733     // local plane representing "horizontal".  This should give us the
734     // local direction for moving "south".
735     MAT3_SET_VEC(minus_z, 0.0, 0.0, -1.0);
736     map_vec_onto_cur_surface_plane(local_up, v0, minus_z, surface_south);
737
738     MAT3_NORMALIZE_VEC(surface_south, ntmp);
739     // printf( "Surface direction directly south %.6f %.6f %.6f\n",
740     //         surface_south[0], surface_south[1], surface_south[2]);
741
742     // now calculate the surface east vector
743     getRotMatrix((double *)TMP, view_up, FG_PI_2);
744     MAT3mult_vec(surface_east, surface_south, TMP);
745     // printf( "Surface direction directly east %.6f %.6f %.6f\n",
746     //         surface_east[0], surface_east[1], surface_east[2]);
747     // printf( "Should be close to zero = %.6f\n", 
748     //         MAT3_DOT_PRODUCT(surface_south, surface_east));
749 #endif // !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
750 }
751
752
753 // Update the "World to Eye" transformation matrix
754 // This is most useful for view frustum culling
755 void FGView::UpdateWorldToEye( FGInterface *f ) {
756     MAT3mat R_Phi, R_Theta, R_Psi, R_Lat, R_Lon, T_view;
757     MAT3mat TMP;
758     MAT3hvec vec;
759
760     if ( use_larcsim_local_to_body ) {
761
762         // Question: hey this is even different then LOCAL[][] above??
763         // Answer: yet another coordinate system, this time the
764         // coordinate system in which we do our view frustum culling.
765
766         AIRCRAFT[0][0] = -f->get_T_local_to_body_22();
767         AIRCRAFT[0][1] = -f->get_T_local_to_body_23();
768         AIRCRAFT[0][2] = f->get_T_local_to_body_21();
769         AIRCRAFT[0][3] = 0.0;
770         AIRCRAFT[1][0] = f->get_T_local_to_body_32();
771         AIRCRAFT[1][1] = f->get_T_local_to_body_33();
772         AIRCRAFT[1][2] = -f->get_T_local_to_body_31();
773         AIRCRAFT[1][3] = 0.0;
774         AIRCRAFT[2][0] = f->get_T_local_to_body_12();
775         AIRCRAFT[2][1] = f->get_T_local_to_body_13();
776         AIRCRAFT[2][2] = -f->get_T_local_to_body_11();
777         AIRCRAFT[2][3] = 0.0;
778         AIRCRAFT[3][0] = AIRCRAFT[3][1] = AIRCRAFT[3][2] = AIRCRAFT[3][3] = 0.0;
779         AIRCRAFT[3][3] = 1.0;
780
781     } else {
782
783         // Roll Matrix
784         MAT3_SET_HVEC(vec, 0.0, 0.0, -1.0, 1.0);
785         MAT3rotate(R_Phi, vec, f->get_Phi());
786         // printf("Roll matrix (Phi)\n");
787         // MAT3print(R_Phi, stdout);
788
789         // Pitch Matrix
790         MAT3_SET_HVEC(vec, 1.0, 0.0, 0.0, 1.0);
791         MAT3rotate(R_Theta, vec, f->get_Theta());
792         // printf("\nPitch matrix (Theta)\n");
793         // MAT3print(R_Theta, stdout);
794
795         // Yaw Matrix
796         MAT3_SET_HVEC(vec, 0.0, -1.0, 0.0, 1.0);
797         MAT3rotate(R_Psi, vec, f->get_Psi() + FG_PI /* - view_offset */ );
798         // MAT3rotate(R_Psi, vec, f->get_Psi() + FG_PI - view_offset );
799         // printf("\nYaw matrix (Psi)\n");
800         // MAT3print(R_Psi, stdout);
801
802         // aircraft roll/pitch/yaw
803         MAT3mult(TMP, R_Phi, R_Theta);
804         MAT3mult(AIRCRAFT, TMP, R_Psi);
805
806     } // if ( use_larcsim_local_to_body )
807
808 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
809         
810     // printf("AIRCRAFT matrix\n");
811     // MAT3print(AIRCRAFT, stdout);
812
813     // View rotation matrix relative to current aircraft orientation
814     MAT3_SET_HVEC(vec, 0.0, -1.0, 0.0, 1.0);
815     MAT3mult_vec(vec, vec, AIRCRAFT);
816     // printf("aircraft up vector = %.2f %.2f %.2f\n", 
817     //        vec[0], vec[1], vec[2]);
818     MAT3rotate(TMP, vec, -view_offset );
819     MAT3mult(VIEW_OFFSET, AIRCRAFT, TMP);
820     // printf("VIEW_OFFSET matrix\n");
821     // MAT3print(VIEW_OFFSET, stdout);
822
823     // View position in scenery centered coordinates
824     MAT3_SET_HVEC(vec, view_pos.x(), view_pos.y(), view_pos.z(), 1.0);
825     MAT3translate(T_view, vec);
826     // printf("\nTranslation matrix\n");
827     // MAT3print(T_view, stdout);
828
829     // Latitude
830     MAT3_SET_HVEC(vec, 1.0, 0.0, 0.0, 1.0);
831     // R_Lat = rotate about X axis
832     MAT3rotate(R_Lat, vec, f->get_Latitude());
833     // printf("\nLatitude matrix\n");
834     // MAT3print(R_Lat, stdout);
835
836     // Longitude
837     MAT3_SET_HVEC(vec, 0.0, 0.0, 1.0, 1.0);
838     // R_Lon = rotate about Z axis
839     MAT3rotate(R_Lon, vec, f->get_Longitude() - FG_PI_2 );
840     // printf("\nLongitude matrix\n");
841     // MAT3print(R_Lon, stdout);
842
843     // lon/lat
844     MAT3mult(WORLD, R_Lat, R_Lon);
845     // printf("\nworld\n");
846     // MAT3print(WORLD, stdout);
847
848     MAT3mult(EYE_TO_WORLD, VIEW_OFFSET, WORLD);
849     MAT3mult(EYE_TO_WORLD, EYE_TO_WORLD, T_view);
850     // printf("\nEye to world\n");
851     // MAT3print(EYE_TO_WORLD, stdout);
852
853     MAT3invert(WORLD_TO_EYE, EYE_TO_WORLD);
854     // printf("\nWorld to eye\n");
855     // MAT3print(WORLD_TO_EYE, stdout);
856
857     // printf( "\nview_pos = %.2f %.2f %.2f\n", 
858     //         view_pos.x, view_pos.y, view_pos.z );
859
860     // MAT3_SET_HVEC(eye, 0.0, 0.0, 0.0, 1.0);
861     // MAT3mult_vec(vec, eye, EYE_TO_WORLD);
862     // printf("\neye -> world = %.2f %.2f %.2f\n", vec[0], vec[1], vec[2]);
863
864     // MAT3_SET_HVEC(vec1, view_pos.x, view_pos.y, view_pos.z, 1.0);
865     // MAT3mult_vec(vec, vec1, WORLD_TO_EYE);
866     // printf( "\nabs_view_pos -> eye = %.2f %.2f %.2f\n", 
867     //         vec[0], vec[1], vec[2]);
868 #else  // FG_VIEW_INLINE_OPTIMIZATIONS
869         
870     MAT3_SET_HVEC(vec, -AIRCRAFT[1][0], -AIRCRAFT[1][1], -AIRCRAFT[1][2], -AIRCRAFT[1][3]);
871     getRotMatrix((double *)TMP, vec, -view_offset );
872     MAT3mult(VIEW_OFFSET, AIRCRAFT, TMP);
873     // MAT3print_formatted(VIEW_OFFSET, stdout, "VIEW_OFFSET matrix:\n",
874     //                                   NULL, "%#8.6f  ", "\n");
875
876     // Build spherical to cartesian transform matrix directly
877     double *mat = (double *)WORLD; //T_view; //WORLD;
878     double cos_lat = f->get_cos_latitude(); //cos(f->get_Latitude());
879     double sin_lat = f->get_sin_latitude(); //sin(f->get_Latitude());
880     // using trig identities  this:
881     //  mat[0]  =  cos(f->get_Longitude() - FG_PI_2);//cos_lon;
882     //  mat[1]  =  sin(f->get_Longitude() - FG_PI_2);//sin_lon;
883     // becomes this: :-)
884     mat[0]  =  f->get_sin_longitude(); //cos_lon;
885     mat[1]  = -f->get_cos_longitude(); //sin_lon;
886     mat[4]  = -cos_lat*mat[1]; //mat[1]=sin_lon;
887     mat[5]  =  cos_lat*mat[0]; //mat[0]=cos_lon;
888     mat[6]  =  sin_lat;
889     mat[8]  =  sin_lat*mat[1]; //mat[1]=sin_lon;
890     mat[9]  = -sin_lat*mat[0]; //mat[0]=cos_lon;
891     mat[10] =  cos_lat;
892
893     // BUILD EYE_TO_WORLD = AIRCRAFT * WORLD
894     // and WORLD_TO_EYE = Inverse( EYE_TO_WORLD) concurrently
895     // by Transposing the 3x3 rotation sub-matrix
896     WORLD_TO_EYE[0][0] = EYE_TO_WORLD[0][0] =
897         VIEW_OFFSET[0][0]*mat[0] + VIEW_OFFSET[0][1]*mat[4] + VIEW_OFFSET[0][2]*mat[8];
898         
899     WORLD_TO_EYE[1][0] = EYE_TO_WORLD[0][1] =
900         VIEW_OFFSET[0][0]*mat[1] + VIEW_OFFSET[0][1]*mat[5] + VIEW_OFFSET[0][2]*mat[9];
901         
902     WORLD_TO_EYE[2][0] = EYE_TO_WORLD[0][2] =
903         VIEW_OFFSET[0][1]*mat[6] + VIEW_OFFSET[0][2]*mat[10];
904         
905     WORLD_TO_EYE[0][1] = EYE_TO_WORLD[1][0] =
906         VIEW_OFFSET[1][0]*mat[0] + VIEW_OFFSET[1][1]*mat[4] + VIEW_OFFSET[1][2]*mat[8];
907         
908     WORLD_TO_EYE[1][1] = EYE_TO_WORLD[1][1] =
909         VIEW_OFFSET[1][0]*mat[1] + VIEW_OFFSET[1][1]*mat[5] + VIEW_OFFSET[1][2]*mat[9];
910         
911     WORLD_TO_EYE[2][1] = EYE_TO_WORLD[1][2] =
912         VIEW_OFFSET[1][1]*mat[6] + VIEW_OFFSET[1][2]*mat[10];
913         
914     WORLD_TO_EYE[0][2] = EYE_TO_WORLD[2][0] =
915         VIEW_OFFSET[2][0]*mat[0] + VIEW_OFFSET[2][1]*mat[4] + VIEW_OFFSET[2][2]*mat[8];
916         
917     WORLD_TO_EYE[1][2] = EYE_TO_WORLD[2][1] =
918         VIEW_OFFSET[2][0]*mat[1] + VIEW_OFFSET[2][1]*mat[5] + VIEW_OFFSET[2][2]*mat[9];
919         
920     WORLD_TO_EYE[2][2] = EYE_TO_WORLD[2][2] =
921         VIEW_OFFSET[2][1]*mat[6] + VIEW_OFFSET[2][2]*mat[10];
922         
923     // TRANSLATE TO VIEW POSITION
924     EYE_TO_WORLD[3][0] = view_pos.x();
925     EYE_TO_WORLD[3][1] = view_pos.y();
926     EYE_TO_WORLD[3][2] = view_pos.z();
927         
928     // FILL 0 ENTRIES
929     WORLD_TO_EYE[0][3] = WORLD_TO_EYE[1][3] = WORLD_TO_EYE[2][3] = 
930         EYE_TO_WORLD[0][3] = EYE_TO_WORLD[1][3] = EYE_TO_WORLD[2][3] = 0.0;
931
932     // FILL UNITY ENTRIES
933     WORLD_TO_EYE[3][3] = EYE_TO_WORLD[3][3] = 1.0;
934         
935     /* MAKE THE INVERTED TRANSLATIONS */
936     mat = (double *)EYE_TO_WORLD;
937     WORLD_TO_EYE[3][0] = -mat[12]*mat[0]
938         -mat[13]*mat[1]
939         -mat[14]*mat[2];
940         
941     WORLD_TO_EYE[3][1] = -mat[12]*mat[4]
942         -mat[13]*mat[5]
943         -mat[14]*mat[6];
944         
945     WORLD_TO_EYE[3][2] = -mat[12]*mat[8]
946         -mat[13]*mat[9]
947         -mat[14]*mat[10];
948         
949     // MAT3print_formatted(EYE_TO_WORLD, stdout, "EYE_TO_WORLD matrix:\n",
950     //                                   NULL, "%#8.6f  ", "\n");
951
952     // MAT3print_formatted(WORLD_TO_EYE, stdout, "WORLD_TO_EYE matrix:\n",
953     //                                   NULL, "%#8.6f  ", "\n");
954
955 #endif // defined(FG_VIEW_INLINE_OPTIMIZATIONS)
956 }
957
958
959 #if 0
960 // Reject non viewable spheres from current View Frustrum by Curt
961 // Olson curt@me.umn.edu and Norman Vine nhv@yahoo.com with 'gentle
962 // guidance' from Steve Baker sbaker@link.com
963 int
964 FGView::SphereClip( const Point3D& cp, const double radius )
965 {
966     double x1, y1;
967
968     MAT3vec eye;        
969     double *mat;
970     double x, y, z;
971
972     x = cp->x;
973     y = cp->y;
974     z = cp->z;
975         
976     mat = (double *)(WORLD_TO_EYE);
977         
978     eye[2] =  x*mat[2] + y*mat[6] + z*mat[10] + mat[14];
979         
980     // Check near and far clip plane
981     if( ( eye[2] > radius ) ||
982         ( eye[2] + radius + current_weather.visibility < 0) )
983         // ( eye[2] + radius + far_plane < 0) )
984     {
985         return 1;
986     }
987         
988     // check right and left clip plane (from eye perspective)
989     x1 = radius * fov_x_clip;
990     eye[0] = (x*mat[0] + y*mat[4] + z*mat[8] + mat[12]) * slope_x;
991     if( (eye[2] > -(eye[0]+x1)) || (eye[2] > (eye[0]-x1)) ) {
992         return(1);
993     }
994         
995     // check bottom and top clip plane (from eye perspective)
996     y1 = radius * fov_y_clip;
997     eye[1] = (x*mat[1] + y*mat[5] + z*mat[9] + mat[13]) * slope_y; 
998     if( (eye[2] > -(eye[1]+y1)) || (eye[2] > (eye[1]-y1)) ) {
999         return 1;
1000     }
1001
1002     return 0;
1003 }
1004 #endif
1005
1006
1007 // Destructor
1008 FGView::~FGView( void ) {
1009 }
1010
1011
1012 // $Log$
1013 // Revision 1.35  1999/04/03 04:21:04  curt
1014 // Integration of Steve's plib conglomeration.
1015 // Optimizations (tm) by Norman Vine.
1016 //
1017 // Revision 1.34  1999/03/08 21:56:41  curt
1018 // Added panel changes sent in by Friedemann.
1019 // Added a splash screen randomization since we have several nice splash screens.
1020 //
1021 // Revision 1.33  1999/02/05 21:29:14  curt
1022 // Modifications to incorporate Jon S. Berndts flight model code.
1023 //
1024 // Revision 1.32  1999/01/07 20:25:12  curt
1025 // Updated struct fgGENERAL to class FGGeneral.
1026 //
1027 // Revision 1.31  1998/12/11 20:26:28  curt
1028 // Fixed view frustum culling accuracy bug so we can look out the sides and
1029 // back without tri-stripes dropping out.
1030 //
1031 // Revision 1.30  1998/12/09 18:50:28  curt
1032 // Converted "class fgVIEW" to "class FGView" and updated to make data
1033 // members private and make required accessor functions.
1034 //
1035 // Revision 1.29  1998/12/05 15:54:24  curt
1036 // Renamed class fgFLIGHT to class FGState as per request by JSB.
1037 //
1038 // Revision 1.28  1998/12/03 01:17:20  curt
1039 // Converted fgFLIGHT to a class.
1040 //
1041 // Revision 1.27  1998/11/16 14:00:06  curt
1042 // Added pow() macro bug work around.
1043 // Added support for starting FGFS at various resolutions.
1044 // Added some initial serial port support.
1045 // Specify default log levels in main().
1046 //
1047 // Revision 1.26  1998/11/09 23:39:25  curt
1048 // Tweaks for the instrument panel.
1049 //
1050 // Revision 1.25  1998/11/06 21:18:15  curt
1051 // Converted to new logstream debugging facility.  This allows release
1052 // builds with no messages at all (and no performance impact) by using
1053 // the -DFG_NDEBUG flag.
1054 //
1055 // Revision 1.24  1998/10/18 01:17:19  curt
1056 // Point3D tweaks.
1057 //
1058 // Revision 1.23  1998/10/17 01:34:26  curt
1059 // C++ ifying ...
1060 //
1061 // Revision 1.22  1998/10/16 00:54:03  curt
1062 // Converted to Point3D class.
1063 //
1064 // Revision 1.21  1998/09/17 18:35:33  curt
1065 // Added F8 to toggle fog and F9 to toggle texturing.
1066 //
1067 // Revision 1.20  1998/09/08 15:04:35  curt
1068 // Optimizations by Norman Vine.
1069 //
1070 // Revision 1.19  1998/08/20 20:32:34  curt
1071 // Reshuffled some of the code in and around views.[ch]xx
1072 //
1073 // Revision 1.18  1998/07/24 21:57:02  curt
1074 // Set near clip plane to 0.5 meters when close to the ground.  Also, let the view get a bit closer to the ground before hitting the hard limit.
1075 //
1076 // Revision 1.17  1998/07/24 21:39:12  curt
1077 // Debugging output tweaks.
1078 // Cast glGetString to (char *) to avoid compiler errors.
1079 // Optimizations to fgGluLookAt() by Norman Vine.
1080 //
1081 // Revision 1.16  1998/07/13 21:01:41  curt
1082 // Wrote access functions for current fgOPTIONS.
1083 //
1084 // Revision 1.15  1998/07/12 03:14:43  curt
1085 // Added ground collision detection.
1086 // Did some serious horsing around to be able to "hug" the ground properly
1087 //   and still be able to take off.
1088 // Set the near clip plane to 1.0 meters when less than 10 meters above the
1089 //   ground.
1090 // Did some serious horsing around getting the initial airplane position to be
1091 //   correct based on rendered terrain elevation.
1092 // Added a little cheat/hack that will prevent the view position from ever
1093 //   dropping below the terrain, even when the flight model doesn't quite
1094 //   put you as high as you'd like.
1095 //
1096 // Revision 1.14  1998/07/08 14:45:08  curt
1097 // polar3d.h renamed to polar3d.hxx
1098 // vector.h renamed to vector.hxx
1099 // updated audio support so it waits to create audio classes (and tie up
1100 //   /dev/dsp) until the mpg123 player is finished.
1101 //
1102 // Revision 1.13  1998/07/04 00:52:27  curt
1103 // Add my own version of gluLookAt() (which is nearly identical to the
1104 // Mesa/glu version.)  But, by calculating the Model View matrix our selves
1105 // we can save this matrix without having to read it back in from the video
1106 // card.  This hopefully allows us to save a few cpu cycles when rendering
1107 // out the fragments because we can just use glLoadMatrixd() with the
1108 // precalculated matrix for each tile rather than doing a push(), translate(),
1109 // pop() for every fragment.
1110 //
1111 // Panel status defaults to off for now until it gets a bit more developed.
1112 //
1113 // Extract OpenGL driver info on initialization.
1114 //
1115 // Revision 1.12  1998/06/03 00:47:15  curt
1116 // Updated to compile in audio support if OSS available.
1117 // Updated for new version of Steve's audio library.
1118 // STL includes don't use .h
1119 // Small view optimizations.
1120 //
1121 // Revision 1.11  1998/05/27 02:24:05  curt
1122 // View optimizations by Norman Vine.
1123 //
1124 // Revision 1.10  1998/05/17 16:59:03  curt
1125 // First pass at view frustum culling now operational.
1126 //
1127 // Revision 1.9  1998/05/16 13:08:37  curt
1128 // C++ - ified views.[ch]xx
1129 // Shuffled some additional view parameters into the fgVIEW class.
1130 // Changed tile-radius to tile-diameter because it is a much better
1131 //   name.
1132 // Added a WORLD_TO_EYE transformation to views.cxx.  This allows us
1133 //  to transform world space to eye space for view frustum culling.
1134 //
1135 // Revision 1.8  1998/05/02 01:51:01  curt
1136 // Updated polartocart conversion routine.
1137 //
1138 // Revision 1.7  1998/04/30 12:34:20  curt
1139 // Added command line rendering options:
1140 //   enable/disable fog/haze
1141 //   specify smooth/flat shading
1142 //   disable sky blending and just use a solid color
1143 //   enable wireframe drawing mode
1144 //
1145 // Revision 1.6  1998/04/28 01:20:23  curt
1146 // Type-ified fgTIME and fgVIEW.
1147 // Added a command line option to disable textures.
1148 //
1149 // Revision 1.5  1998/04/26 05:10:04  curt
1150 // "struct fgLIGHT" -> "fgLIGHT" because fgLIGHT is typedef'd.
1151 //
1152 // Revision 1.4  1998/04/25 22:04:53  curt
1153 // Use already calculated LaRCsim values to create the roll/pitch/yaw
1154 // transformation matrix (we call it LOCAL)
1155 //
1156 // Revision 1.3  1998/04/25 20:24:02  curt
1157 // Cleaned up initialization sequence to eliminate interdependencies
1158 // between sun position, lighting, and view position.  This creates a
1159 // valid single pass initialization path.
1160 //
1161 // Revision 1.2  1998/04/24 00:49:22  curt
1162 // Wrapped "#include <config.h>" in "#ifdef HAVE_CONFIG_H"
1163 // Trying out some different option parsing code.
1164 // Some code reorganization.
1165 //
1166 // Revision 1.1  1998/04/22 13:25:45  curt
1167 // C++ - ifing the code.
1168 // Starting a bit of reorganization of lighting code.
1169 //
1170 // Revision 1.16  1998/04/18 04:11:29  curt
1171 // Moved fg_debug to it's own library, added zlib support.
1172 //
1173 // Revision 1.15  1998/02/20 00:16:24  curt
1174 // Thursday's tweaks.
1175 //
1176 // Revision 1.14  1998/02/09 15:07:50  curt
1177 // Minor tweaks.
1178 //
1179 // Revision 1.13  1998/02/07 15:29:45  curt
1180 // Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1181 // <chotchkiss@namg.us.anritsu.com>
1182 //
1183 // Revision 1.12  1998/01/29 00:50:28  curt
1184 // Added a view record field for absolute x, y, z position.
1185 //
1186 // Revision 1.11  1998/01/27 00:47:58  curt
1187 // Incorporated Paul Bleisch's <pbleisch@acm.org> new debug message
1188 // system and commandline/config file processing code.
1189 //
1190 // Revision 1.10  1998/01/19 19:27:09  curt
1191 // Merged in make system changes from Bob Kuehne <rpk@sgi.com>
1192 // This should simplify things tremendously.
1193 //
1194 // Revision 1.9  1998/01/13 00:23:09  curt
1195 // Initial changes to support loading and management of scenery tiles.  Note,
1196 // there's still a fair amount of work left to be done.
1197 //
1198 // Revision 1.8  1997/12/30 22:22:33  curt
1199 // Further integration of event manager.
1200 //
1201 // Revision 1.7  1997/12/30 20:47:45  curt
1202 // Integrated new event manager with subsystem initializations.
1203 //
1204 // Revision 1.6  1997/12/22 04:14:32  curt
1205 // Aligned sky with sun so dusk/dawn effects can be correct relative to the sun.
1206 //
1207 // Revision 1.5  1997/12/18 04:07:02  curt
1208 // Worked on properly translating and positioning the sky dome.
1209 //
1210 // Revision 1.4  1997/12/17 23:13:36  curt
1211 // Began working on rendering a sky.
1212 //
1213 // Revision 1.3  1997/12/15 23:54:50  curt
1214 // Add xgl wrappers for debugging.
1215 // Generate terrain normals on the fly.
1216 //
1217 // Revision 1.2  1997/12/10 22:37:48  curt
1218 // Prepended "fg" on the name of all global structures that didn't have it yet.
1219 // i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
1220 //
1221 // Revision 1.1  1997/08/27 21:31:17  curt
1222 // Initial revision.
1223 //