]> git.mxchange.org Git - flightgear.git/blob - src/Main/main.cxx
34edfd7fba47480f7b89c1f4b46dac797e2b8af9
[flightgear.git] / src / Main / main.cxx
1 // main.cxx -- top level sim routines
2 //
3 // Written by Curtis Olson for OpenGL, started May 1997.
4 //
5 // Copyright (C) 1997 - 1999  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #ifdef FG_MATH_EXCEPTION_CLASH
29 #  include <math.h>
30 #endif
31
32 #ifdef HAVE_WINDOWS_H
33 #  include <windows.h>                     
34 #  include <float.h>                    
35 #endif
36
37 #include <GL/glut.h>
38 #include <simgear/xgl/xgl.h>
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <string>
43
44 #ifdef HAVE_STDLIB_H
45 #   include <stdlib.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 #  include <sys/stat.h>         // for stat()
50 #endif
51
52 #ifdef HAVE_UNISTD_H
53 #  include <unistd.h>           // for stat()
54 #endif
55
56 #include <plib/pu.h>
57 #include <plib/ssg.h>
58
59 #ifdef ENABLE_AUDIO_SUPPORT
60 #  include <plib/sl.h>
61 #  include <plib/sm.h>
62 #endif
63
64 #include <simgear/constants.h>  // for VERSION
65 #include <simgear/debug/logstream.hxx>
66 #include <simgear/math/polar3d.hxx>
67 #include <simgear/math/sg_random.h>
68 #include <simgear/misc/fgpath.hxx>
69 #include <simgear/sky/sky.hxx>
70 #include <simgear/timing/sg_time.hxx>
71 #include <simgear/timing/lowleveltime.h>
72
73 #include <Include/general.hxx>
74
75 #include <Aircraft/aircraft.hxx>
76
77 #include <Autopilot/newauto.hxx>
78 #include <Cockpit/cockpit.hxx>
79 #include <Cockpit/radiostack.hxx>
80 #include <Cockpit/steam.hxx>
81
82 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
83 #include <GUI/gui.h>
84 #include <Joystick/joystick.hxx>
85 #ifdef FG_NETWORK_OLK
86 #include <NetworkOLK/network.h>
87 #endif
88 #include <Scenery/scenery.hxx>
89 #include <Scenery/tilemgr.hxx>
90 #include <Time/event.hxx>
91 #include <Time/fg_timer.hxx>
92 #include <Time/light.hxx>
93 #include <Time/sunpos.hxx>
94 #include <Time/tmp.hxx>
95
96 // begin - added Venky
97 //    $$$ begin - added VS Renganathan
98 #include <simgear/misc/fgstream.hxx>
99 #include <FDM/flight.hxx>
100 #include <FDM/ADA.hxx>
101 void fgLoadDCS (void);
102 void fgUpdateDCS (void);
103 ssgSelector *ship_sel=NULL;
104 // upto 32 instances of a same object can be loaded.
105 ssgTransform *ship_pos[32];
106 double obj_lat[32],obj_lon[32],obj_alt[32];
107 int objc=0;
108 //    $$$ end - added VS Renganathan
109 // end - added Venky
110
111 #ifndef FG_OLD_WEATHER
112 #  include <WeatherCM/FGLocalWeatherDatabase.h>
113 #else
114 #  include <Weather/weather.hxx>
115 #endif
116
117 #include "version.h"
118
119 #include "bfi.hxx"
120 #include "fg_init.hxx"
121 #include "fg_io.hxx"
122 #include "globals.hxx"
123 #include "keyboard.hxx"
124 #include "splash.hxx"
125
126 #ifdef macintosh
127 #  include <console.h>          // -dw- for command line dialog
128 #endif
129
130
131 // This is a record containing a bit of global housekeeping information
132 FGGeneral general;
133
134 // Specify our current idle function state.  This is used to run all
135 // our initializations out of the glutIdleLoop() so that we can get a
136 // splash screen up and running right away.
137 static int idle_state = 0;
138 static long global_multi_loop;
139
140 // attempt to avoid a large bounce at startup
141 static bool initial_freeze = true;
142
143 // forward declaration
144 void fgReshape( int width, int height );
145
146 // Global structures for the Audio library
147 #ifdef ENABLE_AUDIO_SUPPORT
148 slEnvelope pitch_envelope ( 1, SL_SAMPLE_ONE_SHOT ) ;
149 slEnvelope volume_envelope ( 1, SL_SAMPLE_ONE_SHOT ) ;
150 slScheduler *audio_sched;
151 smMixer *audio_mixer;
152 slSample *s1;
153 slSample *s2;
154 #endif
155
156
157 // ssg variables
158 ssgRoot *scene = NULL;
159 ssgBranch *terrain = NULL;
160
161 // aircraft model stuff
162 ssgSelector *acmodel_selector = NULL;
163 ssgTransform *acmodel_pos = NULL;
164 ssgSelector *prop_selector = NULL;
165 ssgSelector *flaps_selector = NULL;
166 int acmodel_npropsettings;
167 int acmodel_proprpms[4][2];  // different propeller settings
168
169 ssgRoot *lighting = NULL;
170 ssgBranch *ground = NULL;
171 ssgBranch *airport = NULL;
172
173 #ifdef FG_NETWORK_OLK
174 ssgSelector *fgd_sel = NULL;
175 ssgTransform *fgd_pos = NULL;
176 #endif
177
178 // current fdm/position used for view
179 FGInterface cur_view_fdm;
180
181 // Sky structures
182 SGSky *thesky;
183
184 // hack
185 sgMat4 copy_of_ssgOpenGLAxisSwapMatrix =
186 {
187   {  1.0f,  0.0f,  0.0f,  0.0f },
188   {  0.0f,  0.0f, -1.0f,  0.0f },
189   {  0.0f,  1.0f,  0.0f,  0.0f },
190   {  0.0f,  0.0f,  0.0f,  1.0f }
191 } ;
192
193 // The following defines flightgear options. Because glutlib will also
194 // want to parse its own options, those options must not be included here
195 // or they will get parsed by the main program option parser. Hence case
196 // is significant for any option added that might be in conflict with
197 // glutlib's parser.
198 //
199 // glutlib parses for:
200 //    -display
201 //    -direct   (invalid in Win32)
202 //    -geometry
203 //    -gldebug
204 //    -iconized
205 //    -indirect (invalid in Win32)
206 //    -synce
207 //
208 // Note that glutlib depends upon strings while this program's
209 // option parser wants only initial characters followed by numbers
210 // or pathnames.
211 //
212
213
214 ssgSimpleState *default_state;
215 ssgSimpleState *hud_and_panel;
216 ssgSimpleState *menus;
217
218 void fgBuildRenderStates( void ) {
219     default_state = new ssgSimpleState;
220     default_state->ref();
221     default_state->disable( GL_TEXTURE_2D );
222     default_state->enable( GL_CULL_FACE );
223     default_state->enable( GL_COLOR_MATERIAL );
224     default_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
225     default_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
226     default_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
227     default_state->disable( GL_BLEND );
228     default_state->disable( GL_ALPHA_TEST );
229     default_state->disable( GL_LIGHTING );
230
231     hud_and_panel = new ssgSimpleState;
232     hud_and_panel->ref();
233     hud_and_panel->disable( GL_CULL_FACE );
234     hud_and_panel->disable( GL_TEXTURE_2D );
235     hud_and_panel->disable( GL_LIGHTING );
236     hud_and_panel->enable( GL_BLEND );
237
238     menus = new ssgSimpleState;
239     menus->ref();
240     menus->disable( GL_CULL_FACE );
241     menus->disable( GL_TEXTURE_2D );
242     menus->enable( GL_BLEND );
243 }
244
245 // fgFindNode -- a function that finds a named node in an ssg graph
246 ssgEntity *fgFindNode( ssgEntity *node, const char *name ) {
247   if ( node->getName() != NULL && strcmp( name, node->getName() ) == 0 ) {
248     return node;
249   } else if ( node->isAKindOf( ssgTypeBranch() ) ) {
250     ssgEntity *kid = ((ssgBranch*)node)->getKid(0);
251     while (kid != NULL) {
252       ssgEntity *n = fgFindNode(kid, name);
253       if (n != NULL)
254         return n;
255
256       kid = ((ssgBranch*)node)->getNextKid();
257     }
258   }
259
260   return NULL;
261 }
262
263 // fgInitVisuals() -- Initialize various GL/view parameters
264 void fgInitVisuals( void ) {
265     fgLIGHT *l;
266
267     l = &cur_light_params;
268
269 #ifndef GLUT_WRONG_VERSION
270     // Go full screen if requested ...
271     if ( fgGetBool("/sim/startup/fullscreen") ) {
272         glutFullScreen();
273     }
274 #endif
275
276     // If enabled, normal vectors specified with glNormal are scaled
277     // to unit length after transformation.  See glNormal.
278     // glEnable( GL_NORMALIZE );
279
280     glEnable( GL_LIGHTING );
281     glEnable( GL_LIGHT0 );
282     glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
283
284     sgVec3 sunpos;
285     sgSetVec3( sunpos, l->sun_vec[0], l->sun_vec[1], l->sun_vec[2] );
286     ssgGetLight( 0 ) -> setPosition( sunpos );
287
288     // glFogi (GL_FOG_MODE, GL_LINEAR);
289     glFogi (GL_FOG_MODE, GL_EXP2);
290     if ( (fgGetString("/sim/rendering/fog") == "disabled") || 
291          (!fgGetBool("/sim/rendering/shading"))) {
292         // if fastest fog requested, or if flat shading force fastest
293         glHint ( GL_FOG_HINT, GL_FASTEST );
294     } else if ( fgGetString("/sim/rendering/fog") == "nicest" ) {
295         glHint ( GL_FOG_HINT, GL_NICEST );
296     }
297     if ( fgGetBool("/sim/rendering/wireframe") ) {
298         // draw wire frame
299         glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
300     }
301
302     // This is the default anyways, but it can't hurt
303     glFrontFace ( GL_CCW );
304
305     // Just testing ...
306     // glEnable(GL_POINT_SMOOTH);
307     // glEnable(GL_LINE_SMOOTH);
308     // glEnable(GL_POLYGON_SMOOTH);      
309 }
310
311
312 // Update all Visuals (redraws anything graphics related)
313 void fgRenderFrame( void ) {
314     // Update the BFI.
315     FGBFI::update();
316
317     fgLIGHT *l = &cur_light_params;
318     static double last_visibility = -9999;
319
320     static GLfloat fog_exp_density;
321     static GLfloat fog_exp2_density;
322     static GLfloat fog_exp2_punch_through;
323     
324     // double angle;
325     // GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
326     // GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
327     // GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
328     // GLfloat mat_shininess[] = { 10.0 };
329     GLbitfield clear_mask;
330     
331     if ( idle_state != 1000 ) {
332         // still initializing, draw the splash screen
333         if ( fgGetBool("/sim/startup/splash-screen") ) {
334             fgSplashUpdate(0.0);
335         }
336     } else {
337         // idle_state is now 1000 meaning we've finished all our
338         // initializations and are running the main loop, so this will
339         // now work without seg faulting the system.
340
341         // printf("Ground = %.2f  Altitude = %.2f\n", scenery.cur_elev, 
342         //        FG_Altitude * FEET_TO_METER);
343     
344         // this is just a temporary hack, to make me understand Pui
345         // timerText -> setLabel (ctime (&t->cur_time));
346         // end of hack
347
348         // calculate our current position in cartesian space
349         scenery.center = scenery.next_center;
350         // printf("scenery center = %.2f %.2f %.2f\n", scenery.center.x(),
351         //        scenery.center.y(), scenery.center.z());
352
353         FGViewerRPH *pilot_view =
354             (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
355
356         pilot_view->set_geod_view_pos( cur_fdm_state->get_Longitude(), 
357                                        cur_fdm_state->get_Lat_geocentric(), 
358                                        cur_fdm_state->get_Altitude() *
359                                        FEET_TO_METER );
360         pilot_view->set_sea_level_radius( cur_fdm_state->
361                                           get_Sea_level_radius() *
362                                           FEET_TO_METER ); 
363         pilot_view->set_rph( cur_fdm_state->get_Phi(),
364                              cur_fdm_state->get_Theta(),
365                              cur_fdm_state->get_Psi() );
366
367         FGViewerLookAt *chase_view =
368             (FGViewerLookAt *)globals->get_viewmgr()->get_view( 1 );
369
370         sgVec3 po;              // chase view pilot_offset
371         sgVec3 wup;             // chase view world up
372         sgSetVec3( po, 0.0, 0.0, 50.0 );
373         sgCopyVec3( wup, pilot_view->get_world_up() );
374         sgMat4 CXFM;            // chase view + pilot offset xform
375         sgMakeRotMat4( CXFM,
376                        chase_view->get_view_offset() * RAD_TO_DEG -
377                        cur_fdm_state->get_Psi() * RAD_TO_DEG,
378                        wup );
379         sgVec3 npo;             // new pilot offset after rotation
380         sgXformVec3( po, po, pilot_view->get_UP() );
381         sgXformVec3( npo, po, CXFM );
382
383         chase_view->set_geod_view_pos( cur_fdm_state->get_Longitude(), 
384                                        cur_fdm_state->get_Lat_geocentric(), 
385                                        cur_fdm_state->get_Altitude() *
386                                        FEET_TO_METER );
387         chase_view->set_sea_level_radius( cur_fdm_state->
388                                           get_Sea_level_radius() *
389                                           FEET_TO_METER );
390         chase_view->set_pilot_offset( npo[0], npo[1], npo[2] );
391         chase_view->set_view_forward( pilot_view->get_view_pos() ); 
392         chase_view->set_view_up( wup );
393
394 #if 0
395         sgMat4 rph;
396         sgCopyMat4( rph, pilot_view->get_VIEW() );
397         cout << "RPH Matrix = " << endl;
398         int i, j;
399         for ( i = 0; i < 4; i++ ) {
400             for ( j = 0; j < 4; j++ ) {
401                 printf("%10.4f ", rph[i][j]);
402             }
403             cout << endl;
404         }
405
406         sgMat4 la;
407         sgCopyMat4( la, chase_view->get_VIEW() );
408         cout << "LookAt Matrix = " << endl;
409         for ( i = 0; i < 4; i++ ) {
410             for ( j = 0; j < 4; j++ ) {
411                 printf("%10.4f ", la[i][j]);
412             }
413             cout << endl;
414         }
415 #endif
416
417         // update view port
418         fgReshape( fgGetInt("/sim/startup/xsize"),
419                    fgGetInt("/sim/startup/ysize") );
420
421 #if 0
422         // swing and a miss
423
424         if ( ! fgPanelVisible() ) {
425             xglViewport( 0, 0 ,
426                          (GLint)(fgGetInt("/sim/startup/xsize")),
427                          (GLint)(fgGetInt("/sim/startup/ysize")) );
428         } else {
429             int view_h =
430                 int( (current_panel->getViewHeight() -
431                       current_panel->getYOffset())
432                      * (fgGetInt("/sim/startup/ysize") / 768.0) );
433             glViewport( 0, 
434                         (GLint)(fgGetInt("/sim/startup/ysize") - view_h),
435                         (GLint)(fgGetInt("/sim/startup/xsize")),
436                         (GLint)(view_h) );
437         }
438 #endif
439
440         // set the sun position
441         glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
442
443         clear_mask = GL_DEPTH_BUFFER_BIT;
444         if ( fgGetBool("/sim/rendering/wireframe") ) {
445             clear_mask |= GL_COLOR_BUFFER_BIT;
446         }
447
448         if ( fgGetBool("/sim/rendering/skyblend") ) {
449             if ( fgGetBool("/sim/rendering/textures") ) {
450                 // glClearColor(black[0], black[1], black[2], black[3]);
451                 glClearColor(l->adj_fog_color[0], l->adj_fog_color[1], 
452                              l->adj_fog_color[2], l->adj_fog_color[3]);
453                 clear_mask |= GL_COLOR_BUFFER_BIT;
454             }
455         } else {
456             glClearColor(l->sky_color[0], l->sky_color[1], 
457                          l->sky_color[2], l->sky_color[3]);
458             clear_mask |= GL_COLOR_BUFFER_BIT;
459         }
460         glClear( clear_mask );
461
462         // Tell GL we are switching to model view parameters
463
464         // I really should create a derived ssg node or use a call
465         // back or something so that I can draw the sky within the
466         // ssgCullAndDraw() function, but for now I just mimic what
467         // ssg does to set up the model view matrix
468         glMatrixMode(GL_MODELVIEW);
469         glLoadIdentity();
470         ssgSetCamera( (sgVec4 *)globals->get_current_view()->get_VIEW() );
471
472         // set the opengl state to known default values
473         default_state->force();
474
475         // update fog params if visibility has changed
476 #ifndef FG_OLD_WEATHER
477         thesky->set_visibility( WeatherDatabase->getWeatherVisibility() );
478 #else
479         thesky->set_visibility( current_weather.get_visibility() );
480 #endif
481
482         thesky->modify_vis( cur_fdm_state->get_Altitude() * FEET_TO_METER,
483                             ( global_multi_loop * 
484                               fgGetInt("/sim/speed-up") ) /
485                             (double)fgGetInt("/sim/model-hz") );
486
487         double actual_visibility = thesky->get_visibility();
488         // cout << "actual visibility = " << actual_visibility << endl;
489
490         if ( actual_visibility != last_visibility ) {
491             last_visibility = actual_visibility;
492
493             // cout << "----> updating fog params" << endl;
494                 
495             // for GL_FOG_EXP
496             fog_exp_density = -log(0.01 / actual_visibility);
497     
498             // for GL_FOG_EXP2
499             fog_exp2_density = sqrt( -log(0.01) ) / actual_visibility;
500             fog_exp2_punch_through = sqrt( -log(0.01) ) / 
501                 ( actual_visibility * 1.5 );
502         }
503
504         // Set correct opengl fog density
505         glFogf (GL_FOG_DENSITY, fog_exp2_density);
506
507         // update the sky dome
508         if ( fgGetBool("/sim/rendering/skyblend") ) {
509             /* cout << "thesky->repaint() sky_color = "
510                  << cur_light_params.sky_color[0] << " "
511                  << cur_light_params.sky_color[1] << " "
512                  << cur_light_params.sky_color[2] << " "
513                  << cur_light_params.sky_color[3] << endl;
514             cout << "    fog = "
515                  << cur_light_params.fog_color[0] << " "
516                  << cur_light_params.fog_color[1] << " "
517                  << cur_light_params.fog_color[2] << " "
518                  << cur_light_params.fog_color[3] << endl;
519             cout << "    sun_angle = " << cur_light_params.sun_angle
520                  << "    moon_angle = " << cur_light_params.moon_angle
521                  << endl; */
522             thesky->repaint( cur_light_params.sky_color,
523                              cur_light_params.adj_fog_color,
524                              cur_light_params.sun_angle,
525                              cur_light_params.moon_angle,
526                              globals->get_ephem()->getNumPlanets(),
527                              globals->get_ephem()->getPlanets(),
528                              globals->get_ephem()->getNumStars(),
529                              globals->get_ephem()->getStars() );
530  
531             /* cout << "thesky->reposition( view_pos = " << view_pos[0] << " "
532                  << view_pos[1] << " " << view_pos[2] << endl;
533             cout << "    zero_elev = " << zero_elev[0] << " "
534                  << zero_elev[1] << " " << zero_elev[2]
535                  << " lon = " << cur_fdm_state->get_Longitude()
536                  << " lat = " << cur_fdm_state->get_Latitude() << endl;
537             cout << "    sun_rot = " << cur_light_params.sun_rotation
538                  << " gst = " << SGTime::cur_time_params->getGst() << endl;
539             cout << "    sun ra = " << globals->get_ephem()->getSunRightAscension()
540                  << " sun dec = " << globals->get_ephem()->getSunDeclination() 
541                  << " moon ra = " << globals->get_ephem()->getMoonRightAscension()
542                  << " moon dec = " << globals->get_ephem()->getMoonDeclination() << endl; */
543
544             thesky->reposition( globals->get_current_view()->get_view_pos(),
545                                 globals->get_current_view()->get_zero_elev(),
546                                 globals->get_current_view()->get_world_up(),
547                                 cur_fdm_state->get_Longitude(),
548                                 cur_fdm_state->get_Latitude(),
549                                 cur_fdm_state->get_Altitude() * FEET_TO_METER,
550                                 cur_light_params.sun_rotation,
551                                 globals->get_time_params()->getGst(),
552                                 globals->get_ephem()->getSunRightAscension(),
553                                 globals->get_ephem()->getSunDeclination(),
554                                 50000.0,
555                                 globals->get_ephem()->getMoonRightAscension(),
556                                 globals->get_ephem()->getMoonDeclination(),
557                                 50000.0 );
558         }
559
560         glEnable( GL_DEPTH_TEST );
561         if ( fgGetString("/sim/rendering/fog") != "disabled" ) {
562             glEnable( GL_FOG );
563             glFogi( GL_FOG_MODE, GL_EXP2 );
564             glFogfv( GL_FOG_COLOR, l->adj_fog_color );
565         }
566
567         // set lighting parameters
568         GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
569         glLightModelfv( GL_LIGHT_MODEL_AMBIENT, l->scene_ambient );
570         glLightfv( GL_LIGHT0, GL_AMBIENT, black );
571         glLightfv( GL_LIGHT0, GL_DIFFUSE, l->scene_diffuse );
572         // glLightfv(GL_LIGHT0, GL_SPECULAR, white );
573
574         // texture parameters
575         // glEnable( GL_TEXTURE_2D );
576         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
577         glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
578         // set base color (I don't think this is doing anything here)
579         // glMaterialfv (GL_FRONT, GL_AMBIENT, white);
580         //  (GL_FRONT, GL_DIFFUSE, white);
581         // glMaterialfv (GL_FRONT, GL_SPECULAR, white);
582         // glMaterialfv (GL_FRONT, GL_SHININESS, mat_shininess);
583
584         sgVec3 sunpos;
585         sgSetVec3( sunpos, l->sun_vec[0], l->sun_vec[1], l->sun_vec[2] );
586         ssgGetLight( 0 ) -> setPosition( sunpos );
587
588         // glMatrixMode( GL_PROJECTION );
589         // glLoadIdentity();
590         float fov = globals->get_current_view()->get_fov();
591         ssgSetFOV(fov, fov * globals->get_current_view()->get_win_ratio());
592
593         double agl = current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER
594             - scenery.cur_elev;
595
596         // FG_LOG( FG_ALL, FG_INFO, "visibility is " 
597         //         << current_weather.get_visibility() );
598             
599         if ( agl > 10.0 ) {
600             ssgSetNearFar( 10.0f, 120000.0f );
601         } else {
602             ssgSetNearFar( 0.5f, 120000.0f );
603         }
604
605         if ( globals->get_viewmgr()->get_current() == 0 ) {
606             // disable aircraft model
607             acmodel_selector->select(0);
608         } else { 
609             // enable aircraft model and set up its position and orientation
610             acmodel_selector->select(1);
611
612             FGViewerRPH *pilot_view =
613                 (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
614
615             sgMat4 sgTRANS;
616             sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
617
618             sgVec3 ownship_up;
619             sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
620
621             sgMat4 sgROT;
622             sgMakeRotMat4( sgROT, -90.0, ownship_up );
623
624             // sgMat4 sgTMP;
625             // sgMat4 sgTUX;
626             // sgMultMat4( sgTMP, sgROT, pilot_view.VIEW_ROT );
627             // sgMultMat4( sgTUX, sgTMP, sgTRANS );
628
629             // sgTUX = ( sgROT * pilot_view.VIEW_ROT ) * sgTRANS
630             sgMat4 sgTUX;
631             sgCopyMat4( sgTUX, sgROT );
632             sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
633             sgPostMultMat4( sgTUX, sgTRANS );
634         
635             sgCoord tuxpos;
636             sgSetCoord( &tuxpos, sgTUX );
637             acmodel_pos->setTransform( &tuxpos );
638
639             // set up moving parts
640             if (flaps_selector != NULL) {
641               flaps_selector->select( (controls.get_flaps() > 0.5f) ? 1 : 2 );
642             }
643
644             if (prop_selector != NULL) {
645               int propsel_mask = 0;
646               for (int i = 0; i < acmodel_npropsettings; i++) {
647                 if (FGBFI::getRPM() >= acmodel_proprpms[i][0] &&
648                     FGBFI::getRPM() <= acmodel_proprpms[i][1]) {
649                   propsel_mask |= 1 << i;
650                 }
651               }
652               prop_selector->select(propsel_mask);
653             }
654         }
655
656         // $$$ begin - added VS Renganthan 17 Oct 2K
657         fgUpdateDCS();
658         // $$$ end - added VS Renganthan 17 Oct 2K
659
660 # ifdef FG_NETWORK_OLK
661         if ( fgGetBool("/sim/networking/network-olk") ) {
662             sgCoord fgdpos;
663             other = head->next;             /* put listpointer to start  */
664             while ( other != tail) {        /* display all except myself */
665                 if ( strcmp( other->ipadr, fgd_mcp_ip) != 0) {
666                     other->fgd_sel->select(1);
667                     sgSetCoord( &fgdpos, other->sgFGD_COORD );
668                     other->fgd_pos->setTransform( &fgdpos );
669                 }
670                 other = other->next;
671             }
672
673             // fgd_sel->select(1);
674             // sgCopyMat4( sgTUX, current_view.sgVIEW);
675             // sgCoord fgdpos;
676             // sgSetCoord( &fgdpos, sgFGD_VIEW );
677             // fgd_pos->setTransform( &fgdpos);
678         }
679 # endif
680
681         // position tile nodes and update range selectors
682         global_tile_mgr.prep_ssg_nodes();
683
684         if ( fgGetBool("/sim/rendering/skyblend") ) {
685             // draw the sky backdrop
686             thesky->preDraw();
687         }
688
689         // draw the ssg scene
690         glEnable( GL_DEPTH_TEST );
691         ssgCullAndDraw( scene );
692
693         // change state for lighting here
694
695         // draw lighting
696         // Set punch through fog density
697         glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
698
699         ssgCullAndDraw( lighting );
700
701         if ( fgGetBool("/sim/rendering/skyblend") ) {
702             // draw the sky cloud layers
703             thesky->postDraw( cur_fdm_state->get_Altitude() * FEET_TO_METER );
704         }
705
706         // display HUD && Panel
707         glDisable( GL_FOG );
708         glDisable( GL_DEPTH_TEST );
709         // glDisable( GL_CULL_FACE );
710         // glDisable( GL_TEXTURE_2D );
711
712         // update the controls subsystem
713         controls.update();
714
715         hud_and_panel->apply();
716         fgCockpitUpdate();
717
718         // update the panel subsystem
719         if (current_panel != 0)
720           current_panel->update();
721
722         // We can do translucent menus, so why not. :-)
723         menus->apply();
724         glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
725         puDisplay();
726         // glDisable ( GL_BLEND ) ;
727
728         // glEnable( GL_FOG );
729     }
730
731     glutSwapBuffers();
732 }
733
734
735 // Update internal time dependent calculations (i.e. flight model)
736 void fgUpdateTimeDepCalcs() {
737     static bool inited = false;
738
739     fgLIGHT *l = &cur_light_params;
740     int i;
741
742     long multi_loop = 1;
743
744     if ( !globals->get_freeze() && !initial_freeze ) {
745         // conceptually, this could be done for each fdm instance ...
746
747         if ( !inited ) {
748             cur_fdm_state->stamp();
749             inited = true;
750         }
751
752         SGTimeStamp current;
753         current.stamp();
754         long elapsed = current - cur_fdm_state->get_time_stamp();
755         cur_fdm_state->set_time_stamp( current );
756         elapsed += cur_fdm_state->get_remainder();
757         // cout << "elapsed = " << elapsed << endl;
758         // cout << "dt = " << cur_fdm_state->get_delta_t() << endl;
759         multi_loop = (long)(((double)elapsed * 0.000001) /
760                                cur_fdm_state->get_delta_t() );
761         cur_fdm_state->set_multi_loop( multi_loop );
762         long remainder = elapsed - ( (multi_loop*1000000) *
763                                      cur_fdm_state->get_delta_t() );
764         cur_fdm_state->set_remainder( remainder );
765         // cout << "remainder = " << remainder << endl;
766
767         // chop max interations to something reasonable if the sim was
768         // delayed for an excesive amount of time
769         if ( multi_loop > 2.0 / cur_fdm_state->get_delta_t() ) {
770             multi_loop = (int)(2.0 / cur_fdm_state->get_delta_t());
771             cur_fdm_state->set_remainder( 0 );
772         }
773
774         // cout << "multi_loop = " << multi_loop << endl;
775         for ( i = 0; i < multi_loop * fgGetInt("/sim/speed-up"); ++i ) {
776             // run Autopilot system
777             current_autopilot->run();
778
779             // update autopilot
780             cur_fdm_state->update( 1 );
781         }
782         FGSteam::update( multi_loop * fgGetInt("/sim/speed-up") );
783     } else {
784         cur_fdm_state->update( 0 );
785         FGSteam::update( 0 );
786
787         if ( global_tile_mgr.queue_size() == 0 ) {
788             initial_freeze = false;
789         }
790     }
791
792     if ( fgGetString("/sim/view-mode") == "pilot" ) {
793         cur_view_fdm = *cur_fdm_state;
794         // do nothing
795     }
796
797     // update the view angle
798     FGViewer *v = globals->get_current_view();
799     for ( i = 0; i < multi_loop; i++ ) {
800         if ( fabs(v->get_goal_view_offset() - v->get_view_offset()) < 0.05 ) {
801             v->set_view_offset( v->get_goal_view_offset() );
802             break;
803         } else {
804             // move current_view.view_offset towards
805             // current_view.goal_view_offset
806             if ( v->get_goal_view_offset() > v->get_view_offset() )
807             {
808                 if ( v->get_goal_view_offset() - v->get_view_offset() < FG_PI ){
809                     v->inc_view_offset( 0.01 );
810                 } else {
811                     v->inc_view_offset( -0.01 );
812                 }
813             } else {
814                 if ( v->get_view_offset() - v->get_goal_view_offset() < FG_PI ){
815                     v->inc_view_offset( -0.01 );
816                 } else {
817                     v->inc_view_offset( 0.01 );
818                 }
819             }
820             if ( v->get_view_offset() > FG_2PI ) {
821                 v->inc_view_offset( -FG_2PI );
822             } else if ( v->get_view_offset() < 0 ) {
823                 v->inc_view_offset( FG_2PI );
824             }
825         }
826     }
827
828     double tmp = -(l->sun_rotation + FG_PI) 
829         - (cur_fdm_state->get_Psi() -
830            globals->get_current_view()->get_view_offset() );
831     while ( tmp < 0.0 ) {
832         tmp += FG_2PI;
833     }
834     while ( tmp > FG_2PI ) {
835         tmp -= FG_2PI;
836     }
837     /* printf("Psi = %.2f, viewoffset = %.2f sunrot = %.2f rottosun = %.2f\n",
838            FG_Psi * RAD_TO_DEG, current_view.view_offset * RAD_TO_DEG, 
839            -(l->sun_rotation+FG_PI) * RAD_TO_DEG, tmp * RAD_TO_DEG); */
840     l->UpdateAdjFog();
841
842     // Update solar system
843     globals->get_ephem()->update( globals->get_time_params()->getMjd(),
844                                   globals->get_time_params()->getLst(),
845                                   cur_fdm_state->get_Latitude() );
846
847     // Update radio stack model
848     current_radiostack->update();
849 }
850
851
852 void fgInitTimeDepCalcs( void ) {
853     // initialize timer
854
855     // #ifdef HAVE_SETITIMER
856     //   fgTimerInit( 1.0 / fgGetInt("/sim/model-hz"), 
857     //                fgUpdateTimeDepCalcs );
858     // #endif HAVE_SETITIMER
859 }
860
861
862 static const double alt_adjust_ft = 3.758099;
863 static const double alt_adjust_m = alt_adjust_ft * FEET_TO_METER;
864
865
866 // What should we do when we have nothing else to do?  Let's get ready
867 // for the next move and update the display?
868 static void fgMainLoop( void ) {
869     static long remainder = 0;
870     long elapsed;
871 #ifdef FANCY_FRAME_COUNTER
872     int i;
873     double accum;
874 #else
875     static time_t last_time = 0;
876     static int frames = 0;
877 #endif // FANCY_FRAME_COUNTER
878
879     SGTime *t = globals->get_time_params();
880
881     FG_LOG( FG_ALL, FG_DEBUG, "Running Main Loop");
882     FG_LOG( FG_ALL, FG_DEBUG, "======= ==== ====");
883
884 #ifdef FG_NETWORK_OLK
885     if ( fgGetBool("/sim/networking/network-olk") ) {
886         if ( net_is_registered == 0 ) {      // We first have to reg. to fgd
887             // printf("FGD: Netupdate\n");
888             fgd_send_com( "A", FGFS_host);   // Send Mat4 data
889             fgd_send_com( "B", FGFS_host);   // Recv Mat4 data
890         }
891     }
892 #endif
893
894 #if defined( ENABLE_PLIB_JOYSTICK )
895     // Read joystick and update control settings
896     if ( fgGetString("/sim/control-mode") == "joystick" )
897     {
898         fgJoystickRead();
899     }
900 #elif defined( ENABLE_GLUT_JOYSTICK )
901     // Glut joystick support works by feeding a joystick handler
902     // function to glut.  This is taken care of once in the joystick
903     // init routine and we don't have to worry about it again.
904 #endif
905
906 #ifdef FG_OLD_WEATHER
907     current_weather.Update();
908 #endif
909
910     // Fix elevation.  I'm just sticking this here for now, it should
911     // probably move eventually
912
913     /* printf("Before - ground = %.2f  runway = %.2f  alt = %.2f\n",
914            scenery.cur_elev,
915            cur_fdm_state->get_Runway_altitude() * FEET_TO_METER,
916            cur_fdm_state->get_Altitude() * FEET_TO_METER); */
917
918     if ( scenery.cur_elev > -9990 ) {
919         if ( cur_fdm_state->get_Altitude() * FEET_TO_METER < 
920              (scenery.cur_elev + alt_adjust_m - 3.0) ) {
921             // now set aircraft altitude above ground
922             printf("(*) Current Altitude = %.2f < %.2f forcing to %.2f\n", 
923                    cur_fdm_state->get_Altitude() * FEET_TO_METER,
924                    scenery.cur_elev + alt_adjust_m - 3.0,
925                    scenery.cur_elev + alt_adjust_m );
926             fgFDMForceAltitude( fgGetString("/sim/flight-model"), 
927                                 scenery.cur_elev + alt_adjust_m );
928
929             FG_LOG( FG_ALL, FG_DEBUG, 
930                     "<*> resetting altitude to " 
931                     << cur_fdm_state->get_Altitude() * FEET_TO_METER
932                     << " meters" );
933         }
934     }
935
936     /* printf("Adjustment - ground = %.2f  runway = %.2f  alt = %.2f\n",
937            scenery.cur_elev,
938            cur_fdm_state->get_Runway_altitude() * FEET_TO_METER,
939            cur_fdm_state->get_Altitude() * FEET_TO_METER); */
940
941     // update "time"
942     if ( globals->get_warp_delta() != 0 ) {
943         globals->inc_warp( globals->get_warp_delta() );
944     }
945
946     t->update( cur_fdm_state->get_Longitude(),
947                cur_fdm_state->get_Latitude(),
948                globals->get_warp() );
949
950     if ( globals->get_warp_delta() != 0 ) {
951         fgUpdateSkyAndLightingParams();
952     }
953
954     // update magvar model
955     globals->get_mag()->update( cur_fdm_state->get_Longitude(),
956                                 cur_fdm_state->get_Latitude(),
957                                 cur_fdm_state->get_Altitude()* FEET_TO_METER,
958                                 globals->get_time_params()->getJD() );
959
960     // Get elapsed time (in usec) for this past frame
961     elapsed = fgGetTimeInterval();
962     FG_LOG( FG_ALL, FG_DEBUG, 
963             "Elapsed time interval is = " << elapsed 
964             << ", previous remainder is = " << remainder );
965
966     // Calculate frame rate average
967 #ifdef FANCY_FRAME_COUNTER
968     /* old fps calculation */
969     if ( elapsed > 0 ) {
970         double tmp;
971         accum = 0.0;
972         for ( i = FG_FRAME_RATE_HISTORY - 2; i >= 0; i-- ) {
973             tmp = general.get_frame(i);
974             accum += tmp;
975             // printf("frame[%d] = %.2f\n", i, g->frames[i]);
976             general.set_frame(i+1,tmp);
977         }
978         tmp = 1000000.0 / (float)elapsed;
979         general.set_frame(0,tmp);
980         // printf("frame[0] = %.2f\n", general.frames[0]);
981         accum += tmp;
982         general.set_frame_rate(accum / (float)FG_FRAME_RATE_HISTORY);
983         // printf("ave = %.2f\n", general.frame_rate);
984     }
985 #else
986     if ( (t->get_cur_time() != last_time) && (last_time > 0) ) {
987         general.set_frame_rate( frames );
988         FG_LOG( FG_ALL, FG_DEBUG, 
989                 "--> Frame rate is = " << general.get_frame_rate() );
990         frames = 0;
991     }
992     last_time = t->get_cur_time();
993     ++frames;
994 #endif
995
996     // Run flight model
997
998     // Calculate model iterations needed for next frame
999     elapsed += remainder;
1000
1001     global_multi_loop = (long)(((double)elapsed * 0.000001) * 
1002                               fgGetInt("/sim/model-hz"));
1003     remainder = elapsed - ( (global_multi_loop*1000000) / 
1004                             fgGetInt("/sim/model-hz") );
1005     FG_LOG( FG_ALL, FG_DEBUG, 
1006             "Model iterations needed = " << global_multi_loop
1007             << ", new remainder = " << remainder );
1008         
1009     // chop max interations to something reasonable if the sim was
1010     // delayed for an excesive amount of time
1011     if ( global_multi_loop > 2.0 * fgGetInt("/sim/model-hz") ) {
1012         global_multi_loop = (int)(2.0 * fgGetInt("/sim/model-hz") );
1013         remainder = 0;
1014     }
1015
1016     // flight model
1017     if ( global_multi_loop > 0 ) {
1018         fgUpdateTimeDepCalcs();
1019     } else {
1020         FG_LOG( FG_ALL, FG_DEBUG, 
1021                 "Elapsed time is zero ... we're zinging" );
1022     }
1023
1024 #if ! defined( macintosh )
1025     // Do any I/O channel work that might need to be done
1026     fgIOProcess();
1027 #endif
1028
1029     // see if we need to load any new scenery tiles
1030     global_tile_mgr.update( cur_fdm_state->get_Longitude() * RAD_TO_DEG,
1031                             cur_fdm_state->get_Latitude() * RAD_TO_DEG );
1032
1033     // Process/manage pending events
1034     global_events.Process();
1035
1036     // Run audio scheduler
1037 #ifdef ENABLE_AUDIO_SUPPORT
1038     if ( fgGetBool("/sim/sound") && !audio_sched->not_working() ) {
1039
1040         if ( fgGetString("/sim/aircraft") == "c172" ) {
1041             // pitch corresponds to rpm
1042             // volume corresponds to manifold pressure
1043
1044             double rpm_factor;
1045             if ( cur_fdm_state->get_engine(0) != NULL ) {
1046                 rpm_factor = cur_fdm_state->get_engine(0)->get_RPM() / 2500.0;
1047             } else {
1048                 rpm_factor = 1.0;
1049             }
1050             // cout << "rpm = " << cur_fdm_state->get_engine(0)->get_RPM()
1051             //      << endl;
1052
1053             double pitch = 0.3 + rpm_factor * 3.0;
1054         
1055             // don't run at absurdly slow rates -- not realistic
1056             // and sounds bad to boot.  :-)
1057             if (pitch < 0.7) { pitch = 0.7; }
1058             if (pitch > 5.0) { pitch = 5.0; }
1059             // cout << "pitch = " << pitch << endl;
1060
1061             double mp_factor;
1062             if ( cur_fdm_state->get_engine(0) != NULL ) {
1063                 mp_factor = 
1064                     cur_fdm_state->get_engine(0)->get_Manifold_Pressure() / 100;
1065             } else {
1066                 mp_factor = 0.3;
1067             }
1068             /* cout << "mp = " 
1069                  << cur_fdm_state->get_engine(0)->get_Manifold_Pressure()
1070                  << endl; */
1071
1072             double volume = 0.3 + mp_factor;
1073
1074             if ( volume < 0.3 ) { volume = 0.3; }
1075             if ( volume > 1.0 ) { volume = 1.0; }
1076             // cout << "volume = " << volume << endl;
1077
1078             pitch_envelope.setStep  ( 0, 0.01, pitch );
1079             volume_envelope.setStep ( 0, 0.01, volume );
1080         } else {
1081             double param = controls.get_throttle( 0 ) * 2.0 + 1.0;
1082             pitch_envelope.setStep  ( 0, 0.01, param );
1083             volume_envelope.setStep ( 0, 0.01, param );
1084         }
1085
1086         audio_sched -> update();
1087     }
1088 #endif
1089
1090     // redraw display
1091     fgRenderFrame();
1092
1093     FG_LOG( FG_ALL, FG_DEBUG, "" );
1094 }
1095
1096
1097 // This is the top level master main function that is registered as
1098 // our idle funciton
1099 //
1100
1101 // The first few passes take care of initialization things (a couple
1102 // per pass) and once everything has been initialized fgMainLoop from
1103 // then on.
1104
1105 static void fgIdleFunction ( void ) {
1106     // printf("idle state == %d\n", idle_state);
1107
1108     if ( idle_state == 0 ) {
1109         // Initialize the splash screen right away
1110         if ( fgGetBool("/sim/startup/splash-screen") ) {
1111             fgSplashInit();
1112         }
1113         
1114         idle_state++;
1115     } else if ( idle_state == 1 ) {
1116         // Start the intro music
1117 #if !defined(WIN32)
1118         if ( fgGetBool("/sim/startup/intro-music") ) {
1119             string lockfile = "/tmp/mpg123.running";
1120             FGPath mp3file( globals->get_fg_root() );
1121             mp3file.append( "Sounds/intro.mp3" );
1122
1123             string command = "(touch " + lockfile + "; mpg123 "
1124                 + mp3file.str() + "> /dev/null 2>&1; /bin/rm "
1125                 + lockfile + ") &";
1126             FG_LOG( FG_GENERAL, FG_INFO, 
1127                     "Starting intro music: " << mp3file.str() );
1128             system ( command.c_str() );
1129         }
1130 #endif
1131
1132         idle_state++;
1133     } else if ( idle_state == 2 ) {
1134         // These are a few miscellaneous things that aren't really
1135         // "subsystems" but still need to be initialized.
1136
1137 #ifdef USE_GLIDE
1138         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1139             grTexLodBiasValue ( GR_TMU0, 1.0 ) ;
1140         }
1141 #endif
1142
1143         idle_state++;
1144     } else if ( idle_state == 3 ) {
1145         // This is the top level init routine which calls all the
1146         // other subsystem initialization routines.  If you are adding
1147         // a subsystem to flightgear, its initialization call should
1148         // located in this routine.
1149         if( !fgInitSubsystems()) {
1150             FG_LOG( FG_GENERAL, FG_ALERT,
1151                     "Subsystem initializations failed ..." );
1152             exit(-1);
1153         }
1154
1155         idle_state++;
1156     } else if ( idle_state == 4 ) {
1157         // setup OpenGL view parameters
1158         fgInitVisuals();
1159
1160         idle_state++;
1161     } else if ( idle_state == 5 ) {
1162
1163         idle_state++;
1164     } else if ( idle_state == 6 ) {
1165         // Initialize audio support
1166 #ifdef ENABLE_AUDIO_SUPPORT
1167
1168 #if !defined(WIN32)
1169         if ( fgGetBool("/sim/startup/intro-music") ) {
1170             // Let's wait for mpg123 to finish
1171             string lockfile = "/tmp/mpg123.running";
1172             struct stat stat_buf;
1173
1174             FG_LOG( FG_GENERAL, FG_INFO, 
1175                     "Waiting for mpg123 player to finish ..." );
1176             while ( stat(lockfile.c_str(), &stat_buf) == 0 ) {
1177                 // file exist, wait ...
1178                 sleep(1);
1179                 FG_LOG( FG_GENERAL, FG_INFO, ".");
1180             }
1181             FG_LOG( FG_GENERAL, FG_INFO, "");
1182         }
1183 #endif // WIN32
1184
1185         if ( fgGetBool("/sim/sound") ) {
1186             audio_sched = new slScheduler ( 8000 );
1187             audio_mixer = new smMixer;
1188             audio_mixer -> setMasterVolume ( 80 ) ;  /* 80% of max volume. */
1189             audio_sched -> setSafetyMargin ( 1.0 ) ;
1190
1191             FGPath slfile( globals->get_fg_root() );
1192             slfile.append( "Sounds/wasp.wav" );
1193
1194             s1 = new slSample ( (char *)slfile.c_str() );
1195             FG_LOG( FG_GENERAL, FG_INFO,
1196                     "Rate = " << s1 -> getRate()
1197                     << "  Bps = " << s1 -> getBps()
1198                     << "  Stereo = " << s1 -> getStereo() );
1199             audio_sched -> loopSample ( s1 );
1200
1201             if ( audio_sched->not_working() ) {
1202                 // skip
1203             } else {
1204                 pitch_envelope.setStep  ( 0, 0.01, 0.6 );
1205                 volume_envelope.setStep ( 0, 0.01, 0.6 );
1206
1207                 audio_sched -> addSampleEnvelope( s1, 0, 0, 
1208                                                   &pitch_envelope,
1209                                                   SL_PITCH_ENVELOPE );
1210                 audio_sched -> addSampleEnvelope( s1, 0, 1, 
1211                                                   &volume_envelope,
1212                                                   SL_VOLUME_ENVELOPE );
1213             }
1214
1215             // strcpy(slfile, path);
1216             // strcat(slfile, "thunder.wav");
1217             // s2 -> loadFile ( slfile );
1218             // s2 -> adjustVolume(0.5);
1219             // audio_sched -> playSample ( s2 );
1220         }
1221 #endif
1222
1223         // sleep(1);
1224         idle_state = 1000;
1225
1226         cout << "Panel visible = " << fgPanelVisible() << endl;
1227         fgReshape( fgGetInt("/sim/startup/xsize"),
1228                    fgGetInt("/sim/startup/ysize") );
1229     } 
1230
1231     if ( idle_state == 1000 ) {
1232         // We've finished all our initialization steps, from now on we
1233         // run the main loop.
1234
1235         fgMainLoop();
1236     } else {
1237         if ( fgGetBool("/sim/startup/splash-screen") ) {
1238             fgSplashUpdate(0.0);
1239         }
1240     }
1241 }
1242
1243 // options.cxx needs to see this for toggle_panel()
1244 // Handle new window size or exposure
1245 void fgReshape( int width, int height ) {
1246     // for all views
1247     for ( int i = 0; i < globals->get_viewmgr()->size(); ++i ) {
1248         if ( ! fgPanelVisible() || idle_state != 1000 ) {
1249             globals->get_viewmgr()->get_view(i)->
1250                 set_win_ratio( (float)height / (float)width );
1251         } else {
1252             int view_h =
1253                 int((current_panel->getViewHeight() -
1254                      current_panel->getYOffset())
1255                     * (height / 768.0)) + 1;
1256             globals->get_viewmgr()->get_view(i)->
1257                 set_win_ratio( (float)view_h / (float)width );
1258         }
1259     }
1260
1261     if ( ! fgPanelVisible() || idle_state != 1000 ) {
1262         glViewport(0, 0 , (GLint)(width), (GLint)(height) );
1263     } else {
1264         int view_h =
1265             int((current_panel->getViewHeight() - current_panel->getYOffset())
1266                 * (height / 768.0)) + 1;
1267         glViewport(0, (GLint)(height - view_h),
1268                    (GLint)(width), (GLint)(view_h) );
1269     }
1270
1271     fgSetInt("/sim/startup/xsize", width);
1272     fgSetInt("/sim/startup/ysize", height);
1273
1274     float fov = globals->get_current_view()->get_fov();
1275     ssgSetFOV(fov, fov * globals->get_current_view()->get_win_ratio());
1276
1277     fgHUDReshape();
1278 }
1279
1280
1281 // Initialize GLUT and define a main window
1282 int fgGlutInit( int *argc, char **argv ) {
1283
1284 #if !defined( macintosh )
1285     // GLUT will extract all glut specific options so later on we only
1286     // need wory about our own.
1287     glutInit(argc, argv);
1288 #endif
1289
1290     // Define Display Parameters
1291     glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
1292
1293     FG_LOG( FG_GENERAL, FG_INFO, "Opening a window: " <<
1294             fgGetInt("/sim/startup/xsize") << "x"
1295             << fgGetInt("/sim/startup/ysize") );
1296
1297     // Define initial window size
1298     glutInitWindowSize( fgGetInt("/sim/startup/xsize"),
1299                         fgGetInt("/sim/startup/ysize") );
1300
1301     // Initialize windows
1302     if ( !fgGetBool("/sim/startup/game-mode")) {
1303         // Open the regular window
1304         glutCreateWindow("FlightGear");
1305 #ifndef GLUT_WRONG_VERSION
1306     } else {
1307         // Open the cool new 'game mode' window
1308         char game_mode_str[256];
1309         sprintf( game_mode_str, "width=%d height=%d bpp=%d",
1310                  fgGetInt("/sim/startup/xsize"),
1311                  fgGetInt("/sim/startup/ysize"),
1312                  fgGetInt("/sim/rendering/bits-per-pixel"));
1313
1314         FG_LOG( FG_GENERAL, FG_INFO, 
1315                 "game mode params = " << game_mode_str );
1316         glutGameModeString( game_mode_str );
1317         glutEnterGameMode();
1318 #endif
1319     }
1320
1321     // This seems to be the absolute earliest in the init sequence
1322     // that these calls will return valid info.  Too bad it's after
1323     // we've already created and sized out window. :-(
1324     general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
1325     general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
1326     general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
1327     FG_LOG( FG_GENERAL, FG_INFO, general.get_glRenderer() );
1328
1329     GLint tmp;
1330     glGetIntegerv( GL_MAX_TEXTURE_SIZE, &tmp );
1331     general.set_glMaxTexSize( tmp );
1332     FG_LOG ( FG_GENERAL, FG_INFO, "Max texture size = " << tmp );
1333
1334     glGetIntegerv( GL_DEPTH_BITS, &tmp );
1335     general.set_glDepthBits( tmp );
1336     FG_LOG ( FG_GENERAL, FG_INFO, "Depth buffer bits = " << tmp );
1337
1338     return 1;
1339 }
1340
1341
1342 // Initialize GLUT event handlers
1343 int fgGlutInitEvents( void ) {
1344     // call fgReshape() on window resizes
1345     glutReshapeFunc( fgReshape );
1346
1347     // call GLUTkey() on keyboard event
1348     glutKeyboardFunc( GLUTkey );
1349     glutSpecialFunc( GLUTspecialkey );
1350
1351     // call guiMouseFunc() whenever our little rodent is used
1352     glutMouseFunc ( guiMouseFunc );
1353     glutMotionFunc (guiMotionFunc );
1354     glutPassiveMotionFunc (guiMotionFunc );
1355
1356     // call fgMainLoop() whenever there is
1357     // nothing else to do
1358     glutIdleFunc( fgIdleFunction );
1359
1360     // draw the scene
1361     glutDisplayFunc( fgRenderFrame );
1362
1363     return(1);
1364 }
1365
1366
1367 // Main ...
1368 int main( int argc, char **argv ) {
1369
1370 #if defined( macintosh )
1371     freopen ("stdout.txt", "w", stdout );
1372     freopen ("stderr.txt", "w", stderr );
1373     argc = ccommand( &argv );
1374 #endif
1375
1376 #ifdef HAVE_BC5PLUS
1377     _control87(MCW_EM, MCW_EM);  /* defined in float.h */
1378 #endif
1379
1380     // set default log levels
1381     fglog().setLogLevels( FG_ALL, FG_INFO );
1382
1383     string version;
1384 #ifdef FLIGHTGEAR_VERSION
1385     version = FLIGHTGEAR_VERSION;
1386 #else
1387     version = "unknown version";
1388 #endif
1389     FG_LOG( FG_GENERAL, FG_INFO, "FlightGear:  Version "
1390             << version << endl );
1391
1392     // Allocate global data structures.  This needs to happen before
1393     // we parse command line options
1394
1395     SGPropertyNode *props = new SGPropertyNode;
1396     globals = new FGGlobals;
1397     globals->set_props( props );
1398
1399     // seed the random number generater
1400     sg_srandom_time();
1401
1402     SGRoute *route = new SGRoute;
1403     globals->set_route( route );
1404
1405     FGViewMgr *viewmgr = new FGViewMgr;
1406     globals->set_viewmgr( viewmgr );
1407
1408     FGViewerRPH *pv = new FGViewerRPH;
1409     globals->get_viewmgr()->add_view( pv );
1410
1411     FGViewerLookAt *chase = new FGViewerLookAt;
1412     globals->get_viewmgr()->add_view( chase );
1413
1414     string_list *col = new string_list;
1415     globals->set_channel_options_list( col );
1416
1417     // set current view to 0 (first) which is our main pilot view
1418     globals->set_current_view( globals->get_viewmgr()->get_view( 0 ) );
1419
1420     // Scan the config file(s) and command line options to see if
1421     // fg_root was specified (ignore all other options for now)
1422     fgInitFGRoot(argc, argv);
1423
1424     // Initialize the Aircraft directory to "" (UIUC)
1425     aircraft_dir = "";
1426
1427     // Load the configuration parameters
1428     if ( !fgInitConfig(argc, argv) ) {
1429         FG_LOG( FG_GENERAL, FG_ALERT, "Config option parsing failed ..." );
1430         exit(-1);
1431     }
1432
1433     // Initialize the Window/Graphics environment.
1434     if( !fgGlutInit(&argc, argv) ) {
1435         FG_LOG( FG_GENERAL, FG_ALERT, "GLUT initialization failed ..." );
1436         exit(-1);
1437     }
1438
1439     // Initialize the various GLUT Event Handlers.
1440     if( !fgGlutInitEvents() ) {
1441         FG_LOG( FG_GENERAL, FG_ALERT, 
1442                 "GLUT event handler initialization failed ..." );
1443         exit(-1);
1444     }
1445  
1446     // Initialize ssg (from plib).  Needs to come before we do any
1447     // other ssg stuff, but after opengl/glut has been initialized.
1448     ssgInit();
1449
1450     // Initialize the user interface (we need to do this before
1451     // passing off control to glut and before fgInitGeneral to get our
1452     // fonts !!!
1453     guiInit();
1454
1455     // set current_options lon/lat if an airport id is specified
1456     // cout << "3. airport_id = " << fgGetString("/sim/startup/airport-id") << endl;
1457     if ( fgGetString("/sim/startup/airport-id").length() ) {
1458         // fgSetPosFromAirportID( fgGetString("/sim/startup/airport-id") );
1459         fgSetPosFromAirportIDandHdg( fgGetString("/sim/startup/airport-id"),
1460                                      fgGetDouble("/orientation/heading") );
1461     }
1462
1463     // Initialize time
1464     FGPath zone( globals->get_fg_root() );
1465     zone.append( "Timezone" );
1466     SGTime *t = new SGTime( fgGetDouble("/position/longitude") * DEG_TO_RAD,
1467                             fgGetDouble("/position/latitude") * DEG_TO_RAD,
1468                             zone.str() );
1469
1470     // Handle potential user specified time offsets
1471     time_t cur_time = t->get_cur_time();
1472     time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
1473     time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
1474     time_t aircraftLocalTime = 
1475         sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
1476
1477     // Okay, we now have six possible scenarios
1478     int offset = fgGetInt("/sim/startup/time-offset");
1479     const string &offset_type = fgGetString("/sim/startup/time-offset-type");
1480     if (offset_type == "system-offset") {
1481         globals->set_warp( offset );
1482     } else if (offset_type == "gmt-offset") {
1483         globals->set_warp( offset - (currGMT - systemLocalTime) );
1484     } else if (offset_type == "latitude-offset") {
1485         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) );
1486     } else if (offset_type == "system") {
1487         globals->set_warp( offset - cur_time );
1488     } else if (offset_type == "gmt") {
1489         globals->set_warp( offset - currGMT );
1490     } else if (offset_type == "latitude") {
1491         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) - 
1492                            cur_time ); 
1493     } else {
1494         FG_LOG( FG_GENERAL, FG_ALERT,
1495                 "Unsupported offset type " << offset_type );
1496         exit( -1 );
1497     }
1498
1499     FG_LOG( FG_GENERAL, FG_INFO, "After time init, warp = " 
1500             << globals->get_warp() );
1501
1502     globals->set_warp_delta( 0 );
1503
1504     t->update( 0.0, 0.0, globals->get_warp() );
1505
1506     globals->set_time_params( t );
1507
1508     // Do some quick general initializations
1509     if( !fgInitGeneral()) {
1510         FG_LOG( FG_GENERAL, FG_ALERT, 
1511                 "General initializations failed ..." );
1512         exit(-1);
1513     }
1514
1515     FGPath modelpath( globals->get_fg_root() );
1516     ssgModelPath( (char *)modelpath.c_str() );
1517   
1518     // Scene graph root
1519     scene = new ssgRoot;
1520     scene->setName( "Scene" );
1521
1522     lighting = new ssgRoot;
1523     lighting->setName( "Lighting" );
1524
1525     // Initialize the sky
1526     FGPath ephem_data_path( globals->get_fg_root() );
1527     ephem_data_path.append( "Astro" );
1528     SGEphemeris *ephem = new SGEphemeris( ephem_data_path.c_str() );
1529     ephem->update( globals->get_time_params()->getMjd(),
1530                    globals->get_time_params()->getLst(),
1531                    0.0 );
1532     globals->set_ephem( ephem );
1533
1534     FGPath sky_tex_path( globals->get_fg_root() );
1535     sky_tex_path.append( "Textures" );
1536     sky_tex_path.append( "Sky" );
1537     thesky = new SGSky;
1538     thesky->texture_path( sky_tex_path.str() );
1539
1540     thesky->build( 550.0, 550.0,
1541                    globals->get_ephem()->getNumPlanets(), 
1542                    globals->get_ephem()->getPlanets(), 60000.0,
1543                    globals->get_ephem()->getNumStars(),
1544                    globals->get_ephem()->getStars(), 60000.0 );
1545
1546     if ( fgGetBool("/environment/clouds/status") ) {
1547         thesky->add_cloud_layer( 2600.0, 200.0, 50.0, 40000.0,
1548                                  SG_CLOUD_MOSTLY_SUNNY );
1549         thesky->add_cloud_layer( 6000.0, 20.0, 10.0, 40000.0,
1550                                  SG_CLOUD_CIRRUS );
1551         // thesky->add_cloud_layer( 1000.0, 200.0, 50.0,
1552         //                          SG_CLOUD_MOSTLY_SUNNY );
1553         // thesky->add_cloud_layer( 1800.0, 400.0, 100.0, SG_CLOUD_OVERCAST );
1554         // thesky->add_cloud_layer( 5000.0, 20.0, 10.0, SG_CLOUD_CIRRUS );
1555     }
1556
1557     // Initialize MagVar model
1558     SGMagVar *magvar = new SGMagVar();
1559     globals->set_mag( magvar );
1560
1561     // Terrain branch
1562     terrain = new ssgBranch;
1563     terrain->setName( "Terrain" );
1564     scene->addKid( terrain );
1565
1566     // Lighting
1567     ground = new ssgBranch;
1568     ground->setName( "Ground Lighting" );
1569     lighting->addKid( ground );
1570
1571     airport = new ssgBranch;
1572     airport->setName( "Airport Lighting" );
1573     lighting->addKid( airport );
1574
1575     // temporary visible aircraft "own ship"
1576     acmodel_selector = new ssgSelector;
1577     acmodel_pos = new ssgTransform;
1578
1579     string acmodel_path =
1580         fgGetString("/sim/model/path", "Models/Geometry/glider.ac");
1581
1582     string full_model = globals->get_fg_root() + "/"
1583         + acmodel_path;
1584     int pos = full_model.rfind("/");
1585     
1586     FGPath texturepath( full_model.substr(0, pos) );
1587     cout << "Texture path = " << texturepath.str() << endl;
1588     ssgTexturePath( (char *)texturepath.c_str() );
1589
1590     ssgEntity *acmodel_obj = ssgLoad((char *)(acmodel_path.c_str()));
1591
1592     // find moving parts (if this is an MDL model)
1593     flaps_selector = (ssgSelector*)fgFindNode( acmodel_obj, "FLAPS" );
1594     prop_selector  = (ssgSelector*)fgFindNode( acmodel_obj, "PROP"  );
1595
1596     acmodel_npropsettings = 0;
1597     if (prop_selector != NULL) {
1598       for (ssgEntity* kid = prop_selector->getKid(0); kid != NULL;
1599            kid = prop_selector->getNextKid()) {
1600         int prop_low, prop_high;
1601         if ( sscanf(kid->getName(), "PROP_%d_%d", 
1602                     &prop_low, &prop_high) == 2 ) {
1603           prop_low  = (int)((float)prop_low  * (5000.0f / 32767.0f));
1604           prop_high = (int)((float)prop_high * (5000.0f / 32767.0f));
1605           acmodel_proprpms[acmodel_npropsettings][0] = prop_low ;
1606           acmodel_proprpms[acmodel_npropsettings][1] = prop_high;
1607           acmodel_npropsettings++;
1608
1609           FG_LOG( FG_GENERAL, FG_INFO, "PROPELLER SETTING " << prop_low <<
1610                   " " << prop_high );
1611         }
1612       }
1613     }
1614
1615     // align the model properly for FGFS
1616     ssgTransform *acmodel_align = new ssgTransform;
1617     acmodel_align->addKid(acmodel_obj);
1618     sgMat4 rot_matrix;
1619     sgMat4 off_matrix;
1620     sgMat4 res_matrix;
1621     float h_rot = fgGetFloat("/sim/model/h-rotation", 0.0);
1622     float p_rot = fgGetFloat("/sim/model/p-rotation", 0.0);
1623     float r_rot = fgGetFloat("/sim/model/r-rotation", 0.0);
1624     float x_off = fgGetFloat("/sim/model/x-offset", 0.0);
1625     float y_off = fgGetFloat("/sim/model/y-offset", 0.0);
1626     float z_off = fgGetFloat("/sim/model/z-offset", 0.0);
1627     sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
1628     sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
1629     sgMultMat4(res_matrix, off_matrix, rot_matrix);
1630     acmodel_align->setTransform(res_matrix);
1631
1632     acmodel_pos->addKid( acmodel_align );
1633     acmodel_selector->addKid( acmodel_pos );
1634     //ssgFlatten( acmodel_obj );
1635     //ssgStripify( acmodel_selector );
1636     acmodel_selector->clrTraversalMaskBits( SSGTRAV_HOT );
1637     scene->addKid( acmodel_selector );
1638
1639     // $$$ begin - added VS Renganthan 17 Oct 2K
1640     fgLoadDCS();
1641     // $$$ end - added VS Renganthan 17 Oct 2K
1642
1643 #ifdef FG_NETWORK_OLK
1644     // Do the network intialization
1645     if ( fgGetBool("/sim/networking/network-olk") ) {
1646         printf("Multipilot mode %s\n", fg_net_init( scene ) );
1647     }
1648 #endif
1649
1650     // build our custom render states
1651     fgBuildRenderStates();
1652
1653     // pass control off to the master GLUT event handler
1654     glutMainLoop();
1655
1656     // we never actually get here ... but to avoid compiler warnings,
1657     // etc.
1658     return 0;
1659 }
1660
1661
1662 // $$$ end - added VS Renganathan, 15 Oct 2K
1663 //         - added Venky         , 12 Nov 2K
1664
1665 void fgLoadDCS(void) {
1666
1667     ssgEntity *ship_obj = NULL;
1668     // double bz[3];
1669     // int j=0;
1670     char obj_filename[25];
1671
1672     for (int k=0;k<32;k++)
1673     {
1674         ship_pos[k]=NULL;
1675     }
1676
1677     FGPath tile_path( globals->get_fg_root());
1678     tile_path.append( "Scenery" );
1679     tile_path.append( "Objects.txt" );
1680     fg_gzifstream in( tile_path.str() );
1681     if ( ! in.is_open() ) {
1682         FG_LOG( FG_TERRAIN, FG_ALERT, "Cannot open file: " << tile_path.str() );
1683     }
1684
1685     FGPath modelpath( globals->get_fg_root() );
1686     modelpath.append( "Models" );
1687     modelpath.append( "Geometry" );
1688   
1689     FGPath texturepath( globals->get_fg_root() );
1690     texturepath.append( "Models" );
1691     texturepath.append( "Textures" );
1692  
1693     ssgModelPath( (char *)modelpath.c_str() );
1694     ssgTexturePath( (char *)texturepath.c_str() );
1695
1696     ship_sel = new ssgSelector;
1697
1698     char c;
1699     while ( ! in.eof() ) 
1700     {
1701        in >> ::skipws;
1702        if ( in.get( c ) && c == '#' )
1703        { 
1704             in >> skipeol;
1705        }
1706        else 
1707        { 
1708         in.putback(c);
1709                 in >> obj_filename >> obj_lat[objc] >> obj_lon[objc] >> obj_alt[objc];
1710 /*              cout << endl << obj_filename << " " << obj_lat[objc] << " " << obj_lon[objc] <<  " " << obj_alt[objc] << endl;
1711         int chj=getchar();*/
1712                 
1713               obj_lon[objc] *=DEG_TO_RAD;
1714         obj_lat[objc] *=DEG_TO_RAD;
1715     
1716             ship_pos[objc] = new ssgTransform;
1717        
1718        
1719         // type "repeat" in objects.txt to load one more instance of the last object.
1720
1721         if ( strcmp(obj_filename,"repeat") != 0)
1722                   ship_obj = ssgLoadOBJ( obj_filename );
1723       
1724               if ( ship_obj != NULL ) 
1725             {
1726                         ship_pos[objc]->addKid( ship_obj ); // add object to transform node
1727                         ship_sel->addKid( ship_pos[objc] ); // add transform node to selector
1728                         }
1729         else
1730                 FG_LOG( FG_TERRAIN, FG_ALERT, "Cannot open file: " << obj_filename );
1731             
1732         if (in.eof()) break;
1733             objc++;
1734          }
1735      } // while
1736
1737     ship_sel->clrTraversalMaskBits( SSGTRAV_HOT );
1738     scene->addKid( ship_sel ); //add selector node to root node
1739     return;
1740  }
1741
1742
1743 void fgUpdateDCS (void) {
1744
1745     // double eye_lat,eye_lon,eye_alt;
1746     // static double obj_head;
1747     double sl_radius,obj_latgc;
1748     // float nresultmat[4][4];
1749     // sgMat4 Trans,rothead,rotlon,rot180,rotlat,resultmat1,resultmat2,resultmat3;
1750     double bz[3];
1751
1752     // Instantaneous Geodetic Lat/Lon/Alt of moving object
1753     FGADA *fdm = (FGADA *)current_aircraft.fdm_state;
1754     
1755     // Deck should be the first object in objects.txt in case of fdm=ada
1756
1757     if (fgGetString("/sim/flight-model") == "ada")
1758     {
1759       obj_lon[0] = fdm->get_aux5()*DEG_TO_RAD;
1760       obj_lat[0] = fdm->get_aux6()*DEG_TO_RAD;
1761       obj_alt[0] = fdm->get_aux7();
1762     }
1763     
1764     for (int m=0; m<=objc; m++)
1765     {
1766         //cout << endl <<  obj_lat[m]*RAD_TO_DEG << " " << obj_lon[m]*RAD_TO_DEG << " " << obj_alt[m] << " " << objc << endl;
1767         //int v=getchar();
1768
1769         //Geodetic to Geocentric angles for rotation
1770         sgGeodToGeoc(obj_lat[m],obj_alt[m],&sl_radius,&obj_latgc);
1771
1772         //moving object gbs-posn in cartesian coords
1773         Point3D obj_posn = Point3D( obj_lon[m],obj_lat[m],obj_alt[m]);
1774         Point3D obj_pos = sgGeodToCart( obj_posn );
1775
1776         // Translate moving object w.r.t eye
1777         Point3D Objtrans = obj_pos-scenery.center;
1778         bz[0]=Objtrans.x();
1779         bz[1]=Objtrans.y();
1780         bz[2]=Objtrans.z();
1781
1782        // rotate dynamic objects for lat,lon & alt and other motion about its axes
1783         
1784         sgMat4 sgTRANS;
1785         sgMakeTransMat4( sgTRANS, bz[0],bz[1],bz[2]);
1786
1787         sgVec3 ship_fwd,ship_rt,ship_up;
1788         sgSetVec3( ship_fwd, 1.0, 0.0, 0.0);//east,roll
1789         sgSetVec3( ship_rt, 0.0, 1.0, 0.0);//up,pitch
1790         sgSetVec3( ship_up, 0.0, 0.0, 1.0); //north,yaw
1791
1792         sgMat4 sgROT_lon, sgROT_lat, sgROT_hdg;
1793         sgMakeRotMat4( sgROT_lon, obj_lon[m]*RAD_TO_DEG, ship_up );
1794         sgMakeRotMat4( sgROT_lat, 90-obj_latgc*RAD_TO_DEG, ship_rt );
1795         sgMakeRotMat4( sgROT_hdg, 180.0, ship_up );
1796         
1797         sgMat4 sgTUX;
1798         sgCopyMat4( sgTUX, sgROT_hdg );
1799         sgPostMultMat4( sgTUX, sgROT_lat );
1800         sgPostMultMat4( sgTUX, sgROT_lon );
1801         sgPostMultMat4( sgTUX, sgTRANS );
1802
1803         sgCoord shippos;
1804         sgSetCoord(&shippos, sgTUX );
1805         ship_pos[m]->setTransform( &shippos );
1806     }
1807    if ( ship_sel != NULL ) 
1808         ship_sel->select(0xFFFFFFFF);
1809   }
1810
1811 // $$$ end - added VS Renganathan, 15 Oct 2K
1812 //           added Venky         , 12 Nov 2K