]> git.mxchange.org Git - flightgear.git/blob - src/Main/main.cxx
Addition Irix tweaks.
[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 #include <simgear/compiler.h>
29 #include <simgear/misc/exception.hxx>
30
31 #ifdef SG_MATH_EXCEPTION_CLASH
32 #  include <math.h>
33 #endif
34
35 #ifdef HAVE_WINDOWS_H
36 #  include <windows.h>
37 #  include <float.h>
38 #endif
39
40 #include <GL/glut.h>
41 #include <GL/gl.h>
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <string>
46
47 #ifdef HAVE_STDLIB_H
48 #   include <stdlib.h>
49 #endif
50
51 #ifdef HAVE_SYS_STAT_H
52 #  include <sys/stat.h>         // for stat()
53 #endif
54
55 #ifdef HAVE_UNISTD_H
56 #  include <unistd.h>           // for stat()
57 #endif
58
59 // #ifdef HAVE_LIBX11
60 // #  include <GL/glext.h>
61 // #endif
62
63 #include <plib/netChat.h>
64 #include <plib/pu.h>
65 #include <plib/ssg.h>
66
67 #include <simgear/constants.h>  // for VERSION
68 #include <simgear/debug/logstream.hxx>
69 #include <simgear/math/polar3d.hxx>
70 #include <simgear/math/sg_random.h>
71 #include <simgear/misc/sg_path.hxx>
72 #include <simgear/sky/sky.hxx>
73 #include <simgear/timing/sg_time.hxx>
74 #include <simgear/timing/lowleveltime.h>
75
76 #include <Include/general.hxx>
77
78 #include <Aircraft/aircraft.hxx>
79
80 #include <Autopilot/newauto.hxx>
81 #include <Cockpit/cockpit.hxx>
82 #include <Cockpit/radiostack.hxx>
83 #include <Cockpit/steam.hxx>
84
85 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
86 #include <GUI/gui.h>
87 #include <GUI/sgVec3Slider.hxx>
88 // #include <Joystick/joystick.hxx>
89 #ifdef FG_NETWORK_OLK
90 #include <NetworkOLK/network.h>
91 #endif
92 #include <Objects/matlib.hxx>
93 #include <Scenery/scenery.hxx>
94 #include <Scenery/tilemgr.hxx>
95 #ifdef ENABLE_AUDIO_SUPPORT
96 #  include <Sound/soundmgr.hxx>
97 #  include <Sound/morse.hxx>
98 #endif
99 #include <Time/event.hxx>
100 #include <Time/fg_timer.hxx>
101 #include <Time/light.hxx>
102 #include <Time/sunpos.hxx>
103 #include <Time/tmp.hxx>
104
105 #include <Input/input.hxx>
106
107 // ADA
108 #include <simgear/misc/sgstream.hxx>
109 #include <simgear/math/point3d.hxx>
110 #include <FDM/flight.hxx>
111 #include <FDM/ADA.hxx>
112 #include <Scenery/tileentry.hxx>
113 // Should already be inlcluded by gl.h if needed by your platform so
114 // we shouldn't include this here.
115 // #include <GL/glext.h>
116 #if !defined(sgi)
117 // PFNGLPOINTPARAMETERFEXTPROC glPointParameterfEXT = 0;
118 // PFNGLPOINTPARAMETERFVEXTPROC glPointParameterfvEXT = 0;
119 #endif
120 float default_attenuation[3] = {1.0, 0.0, 0.0};
121 //Required for using GL_extensions
122 void fgLoadDCS (void);
123 void fgUpdateDCS (void);
124 ssgSelector *ship_sel=NULL;
125 // upto 32 instances of a same object can be loaded.
126 ssgTransform *ship_pos[32];
127 double obj_lat[32],obj_lon[32],obj_alt[32],obj_pitch[32],obj_roll[32];
128 int objc=0;
129 ssgSelector *lightpoints_brightness = new ssgSelector;
130 ssgTransform *lightpoints_transform = new ssgTransform;
131 FGTileEntry *dummy_tile;
132 sgVec3 rway_ols;
133 // ADA
134
135 #ifndef FG_OLD_WEATHER
136 #  include <WeatherCM/FGLocalWeatherDatabase.h>
137 #else
138 #  include <Weather/weather.hxx>
139 #endif
140
141 #include "version.h"
142
143 #include "fg_init.hxx"
144 #include "fg_io.hxx"
145 #include "fg_props.hxx"
146 #include "globals.hxx"
147 #include "splash.hxx"
148 #include "viewmgr.hxx"
149
150 #ifdef macintosh
151 #  include <console.h>          // -dw- for command line dialog
152 #endif
153
154
155 // This is a record containing a bit of global housekeeping information
156 FGGeneral general;
157
158 // Specify our current idle function state.  This is used to run all
159 // our initializations out of the glutIdleLoop() so that we can get a
160 // splash screen up and running right away.
161 static int idle_state = 0;
162 static long global_multi_loop;
163
164 // attempt to avoid a large bounce at startup
165 static bool initial_freeze = true;
166
167 // forward declaration
168 void fgReshape( int width, int height );
169
170 // Global structures for the Audio library
171 #ifdef ENABLE_AUDIO_SUPPORT
172    static FGSimpleSound *s1;
173    static FGSimpleSound *s2;
174 #endif
175
176
177 // ssg variables
178 ssgRoot *scene = NULL;
179 ssgBranch *terrain = NULL;
180
181 // aircraft model stuff
182 ssgSelector *acmodel_selector = NULL;
183 ssgTransform *acmodel_pos = NULL;
184 ssgSelector *prop_selector = NULL;
185 ssgSelector *flaps_selector = NULL;
186 int acmodel_npropsettings;
187 int acmodel_proprpms[4][2];  // different propeller settings
188
189 ssgRoot *lighting = NULL;
190 ssgBranch *ground = NULL;
191 ssgBranch *airport = NULL;
192
193 #ifdef FG_NETWORK_OLK
194 ssgSelector *fgd_sel = NULL;
195 ssgTransform *fgd_pos = NULL;
196 #endif
197
198 // current fdm/position used for view
199 FGInterface cur_view_fdm;
200
201 // Sky structures
202 SGSky *thesky;
203
204 // hack
205 sgMat4 copy_of_ssgOpenGLAxisSwapMatrix =
206 {
207   {  1.0f,  0.0f,  0.0f,  0.0f },
208   {  0.0f,  0.0f, -1.0f,  0.0f },
209   {  0.0f,  1.0f,  0.0f,  0.0f },
210   {  0.0f,  0.0f,  0.0f,  1.0f }
211 } ;
212
213 // The following defines flightgear options. Because glutlib will also
214 // want to parse its own options, those options must not be included here
215 // or they will get parsed by the main program option parser. Hence case
216 // is significant for any option added that might be in conflict with
217 // glutlib's parser.
218 //
219 // glutlib parses for:
220 //    -display
221 //    -direct   (invalid in Win32)
222 //    -geometry
223 //    -gldebug
224 //    -iconized
225 //    -indirect (invalid in Win32)
226 //    -synce
227 //
228 // Note that glutlib depends upon strings while this program's
229 // option parser wants only initial characters followed by numbers
230 // or pathnames.
231 //
232
233
234 ssgSimpleState *default_state;
235 ssgSimpleState *hud_and_panel;
236 ssgSimpleState *menus;
237
238 void fgBuildRenderStates( void ) {
239     default_state = new ssgSimpleState;
240     default_state->ref();
241     default_state->disable( GL_TEXTURE_2D );
242     default_state->enable( GL_CULL_FACE );
243     default_state->enable( GL_COLOR_MATERIAL );
244     default_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
245     default_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
246     default_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
247     default_state->disable( GL_BLEND );
248     default_state->disable( GL_ALPHA_TEST );
249     default_state->disable( GL_LIGHTING );
250
251     hud_and_panel = new ssgSimpleState;
252     hud_and_panel->ref();
253     hud_and_panel->disable( GL_CULL_FACE );
254     hud_and_panel->disable( GL_TEXTURE_2D );
255     hud_and_panel->disable( GL_LIGHTING );
256     hud_and_panel->enable( GL_BLEND );
257
258     menus = new ssgSimpleState;
259     menus->ref();
260     menus->disable( GL_CULL_FACE );
261     menus->disable( GL_TEXTURE_2D );
262     menus->enable( GL_BLEND );
263 }
264
265 // fgFindNode -- a function that finds a named node in an ssg graph
266 ssgEntity *fgFindNode( ssgEntity *node, const char *name ) {
267   if ( node->getName() != NULL && strcmp( name, node->getName() ) == 0 ) {
268     return node;
269   } else if ( node->isAKindOf( ssgTypeBranch() ) ) {
270     ssgEntity *kid = ((ssgBranch*)node)->getKid(0);
271     while (kid != NULL) {
272       ssgEntity *n = fgFindNode(kid, name);
273       if (n != NULL)
274         return n;
275
276       kid = ((ssgBranch*)node)->getNextKid();
277     }
278   }
279
280   return NULL;
281 }
282
283 // fgInitVisuals() -- Initialize various GL/view parameters
284 void fgInitVisuals( void ) {
285     fgLIGHT *l;
286
287     l = &cur_light_params;
288
289 #ifndef GLUT_WRONG_VERSION
290     // Go full screen if requested ...
291     if ( fgGetBool("/sim/startup/fullscreen") ) {
292         glutFullScreen();
293     }
294 #endif
295
296     // If enabled, normal vectors specified with glNormal are scaled
297     // to unit length after transformation.  See glNormal.
298     // glEnable( GL_NORMALIZE );
299
300     glEnable( GL_LIGHTING );
301     glEnable( GL_LIGHT0 );
302     glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
303
304     sgVec3 sunpos;
305     sgSetVec3( sunpos, l->sun_vec[0], l->sun_vec[1], l->sun_vec[2] );
306     ssgGetLight( 0 ) -> setPosition( sunpos );
307
308     // glFogi (GL_FOG_MODE, GL_LINEAR);
309     glFogi (GL_FOG_MODE, GL_EXP2);
310     if ( (fgGetString("/sim/rendering/fog") == "disabled") || 
311          (!fgGetBool("/sim/rendering/shading"))) {
312         // if fastest fog requested, or if flat shading force fastest
313         glHint ( GL_FOG_HINT, GL_FASTEST );
314     } else if ( fgGetString("/sim/rendering/fog") == "nicest" ) {
315         glHint ( GL_FOG_HINT, GL_NICEST );
316     }
317     if ( fgGetBool("/sim/rendering/wireframe") ) {
318         // draw wire frame
319         glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
320     }
321
322     // This is the default anyways, but it can't hurt
323     glFrontFace ( GL_CCW );
324
325     // Just testing ...
326     // glEnable(GL_POINT_SMOOTH);
327     // glEnable(GL_LINE_SMOOTH);
328     // glEnable(GL_POLYGON_SMOOTH);      
329 }
330
331
332 // For HiRes screen Dumps using Brian Pauls TR Library
333 void trRenderFrame( void ) {
334
335     if ( fgPanelVisible() ) {
336         GLfloat height = fgGetInt("/sim/startup/ysize");
337         GLfloat view_h =
338             (current_panel->getViewHeight() - current_panel->getYOffset())
339             * (height / 768.0) + 1;
340         glTranslatef( 0.0, view_h, 0.0 );
341     }
342
343     static double m_log01      = -log( 0.01 );
344     static double sqrt_m_log01 = sqrt( m_log01 );
345
346     static GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
347     static GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
348
349     fgLIGHT *l = &cur_light_params;
350
351     glClearColor(l->adj_fog_color[0], l->adj_fog_color[1], 
352                  l->adj_fog_color[2], l->adj_fog_color[3]);
353
354     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
355
356     // set the opengl state to known default values
357     default_state->force();
358
359     // update fog params
360     double actual_visibility       = thesky->get_visibility();
361     // GLfloat fog_exp_density        = m_log01 / actual_visibility;
362     GLfloat fog_exp2_density       = sqrt_m_log01 / actual_visibility;
363     GLfloat fog_exp2_punch_through = sqrt_m_log01 / ( actual_visibility * 1.5 );
364
365     glEnable( GL_FOG );
366     glFogf  ( GL_FOG_DENSITY, fog_exp2_density);
367     glFogi  ( GL_FOG_MODE,    GL_EXP2 );
368     glFogfv ( GL_FOG_COLOR,   l->adj_fog_color );
369
370     // GL_LIGHT_MODEL_AMBIENT has a default non-zero value so if
371     // we only update GL_AMBIENT for our lights we will never get
372     // a completely dark scene.  So, we set GL_LIGHT_MODEL_AMBIENT
373     // explicitely to black.
374     glLightModelfv( GL_LIGHT_MODEL_AMBIENT, black );
375
376     ssgGetLight( 0 ) -> setColour( GL_AMBIENT, l->scene_ambient );
377
378     // texture parameters
379     glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
380     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
381
382     // we need a white diffuse light for the phase of the moon
383     ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, white );
384     thesky->preDraw();
385
386     // draw the ssg scene
387     // return to the desired diffuse color
388     ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
389     glEnable( GL_DEPTH_TEST );
390     ssgCullAndDraw( scene );
391
392     // draw the lights
393     glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
394     ssgCullAndDraw( lighting );
395
396     thesky->postDraw( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER );
397
398     // need to do this here as hud_and_panel state is static to
399     // main.cxx  and HUD and Panel routines have to be called with
400     // knowledge of the the TR struct < see gui.cxx::HighResDump()
401     hud_and_panel->apply();
402 }
403
404
405 // Update all Visuals (redraws anything graphics related)
406 void fgRenderFrame( void ) {
407     // Update the default (kludged) properties.
408     fgUpdateProps();
409
410     fgLIGHT *l = &cur_light_params;
411     static double last_visibility = -9999;
412
413     static GLfloat fog_exp_density;
414     static GLfloat fog_exp2_density;
415     static GLfloat fog_exp2_punch_through;
416     
417     // double angle;
418     // GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
419     // GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
420     // GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
421     // GLfloat mat_shininess[] = { 10.0 };
422     GLbitfield clear_mask;
423     
424     if ( idle_state != 1000 ) {
425         // still initializing, draw the splash screen
426         if ( fgGetBool("/sim/startup/splash-screen") ) {
427             fgSplashUpdate(0.0);
428         }
429     } else {
430         // idle_state is now 1000 meaning we've finished all our
431         // initializations and are running the main loop, so this will
432         // now work without seg faulting the system.
433
434         // printf("Ground = %.2f  Altitude = %.2f\n", scenery.cur_elev, 
435         //        FG_Altitude * SG_FEET_TO_METER);
436     
437         // this is just a temporary hack, to make me understand Pui
438         // timerText -> setLabel (ctime (&t->cur_time));
439         // end of hack
440
441         // calculate our current position in cartesian space
442         scenery.center = scenery.next_center;
443         // printf("scenery center = %.2f %.2f %.2f\n", scenery.center.x(),
444         //        scenery.center.y(), scenery.center.z());
445
446         FGViewerRPH *pilot_view =
447             (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
448
449         pilot_view->set_geod_view_pos( cur_fdm_state->get_Longitude(), 
450                                        cur_fdm_state->get_Lat_geocentric(), 
451                                        cur_fdm_state->get_Altitude() *
452                                        SG_FEET_TO_METER );
453         pilot_view->set_sea_level_radius( cur_fdm_state->
454                                           get_Sea_level_radius() *
455                                           SG_FEET_TO_METER ); 
456         pilot_view->set_rph( cur_fdm_state->get_Phi(),
457                              cur_fdm_state->get_Theta(),
458                              cur_fdm_state->get_Psi() );
459
460         if (fgGetString("/sim/flight-model") == "ada") {
461             //+ve x is aft, +ve z is up (see viewer.hxx)
462             pilot_view->set_pilot_offset( -5.0, 0.0, 1.0 ); 
463         }
464
465         FGViewerLookAt *chase_view =
466             (FGViewerLookAt *)globals->get_viewmgr()->get_view( 1 );
467
468         sgVec3 po;              // chase view pilot_offset
469         sgVec3 wup;             // chase view world up
470         sgSetVec3( po, 0.0, 0.0, 100.0 );
471         sgCopyVec3( wup, pilot_view->get_world_up() );
472         sgMat4 CXFM;            // chase view + pilot offset xform
473         sgMakeRotMat4( CXFM,
474                        chase_view->get_view_offset() * SGD_RADIANS_TO_DEGREES -
475                        cur_fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES,
476                        wup );
477         sgVec3 npo;             // new pilot offset after rotation
478         sgVec3 *pPO = PilotOffsetGet();
479         sgXformVec3( po, *pPO, pilot_view->get_UP() );
480         sgXformVec3( npo, po, CXFM );
481
482         chase_view->set_geod_view_pos( cur_fdm_state->get_Longitude(), 
483                                        cur_fdm_state->get_Lat_geocentric(), 
484                                        cur_fdm_state->get_Altitude() *
485                                        SG_FEET_TO_METER );
486         chase_view->set_sea_level_radius( cur_fdm_state->
487                                           get_Sea_level_radius() *
488                                           SG_FEET_TO_METER );
489         chase_view->set_pilot_offset( npo[0], npo[1], npo[2] );
490         chase_view->set_view_forward( pilot_view->get_view_pos() ); 
491         chase_view->set_view_up( wup );
492
493 #if 0
494         sgMat4 rph;
495         sgCopyMat4( rph, pilot_view->get_VIEW() );
496         cout << "RPH Matrix = " << endl;
497         int i, j;
498         for ( i = 0; i < 4; i++ ) {
499             for ( j = 0; j < 4; j++ ) {
500                 printf("%10.4f ", rph[i][j]);
501             }
502             cout << endl;
503         }
504
505         sgMat4 la;
506         sgCopyMat4( la, chase_view->get_VIEW() );
507         cout << "LookAt Matrix = " << endl;
508         for ( i = 0; i < 4; i++ ) {
509             for ( j = 0; j < 4; j++ ) {
510                 printf("%10.4f ", la[i][j]);
511             }
512             cout << endl;
513         }
514 #endif
515
516         // update view port
517         fgReshape( fgGetInt("/sim/startup/xsize"),
518                    fgGetInt("/sim/startup/ysize") );
519
520 #if 0
521         // swing and a miss
522
523         if ( ! fgPanelVisible() ) {
524             xglViewport( 0, 0 ,
525                          (GLint)(fgGetInt("/sim/startup/xsize")),
526                          (GLint)(fgGetInt("/sim/startup/ysize")) );
527         } else {
528             int view_h =
529                 int( (current_panel->getViewHeight() -
530                       current_panel->getYOffset())
531                      * (fgGetInt("/sim/startup/ysize") / 768.0) );
532             glViewport( 0, 
533                         (GLint)(fgGetInt("/sim/startup/ysize") - view_h),
534                         (GLint)(fgGetInt("/sim/startup/xsize")),
535                         (GLint)(view_h) );
536         }
537 #endif
538
539         // set the sun position
540         glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
541
542         clear_mask = GL_DEPTH_BUFFER_BIT;
543         if ( fgGetBool("/sim/rendering/wireframe") ) {
544             clear_mask |= GL_COLOR_BUFFER_BIT;
545         }
546
547         if ( fgGetBool("/sim/rendering/skyblend") ) {
548             if ( fgGetBool("/sim/rendering/textures") ) {
549                 // glClearColor(black[0], black[1], black[2], black[3]);
550                 glClearColor(l->adj_fog_color[0], l->adj_fog_color[1], 
551                              l->adj_fog_color[2], l->adj_fog_color[3]);
552                 clear_mask |= GL_COLOR_BUFFER_BIT;
553             }
554         } else {
555             glClearColor(l->sky_color[0], l->sky_color[1], 
556                          l->sky_color[2], l->sky_color[3]);
557             clear_mask |= GL_COLOR_BUFFER_BIT;
558         }
559         glClear( clear_mask );
560
561         // Tell GL we are switching to model view parameters
562
563         // I really should create a derived ssg node or use a call
564         // back or something so that I can draw the sky within the
565         // ssgCullAndDraw() function, but for now I just mimic what
566         // ssg does to set up the model view matrix
567         glMatrixMode(GL_MODELVIEW);
568         glLoadIdentity();
569         ssgSetCamera( (sgVec4 *)globals->get_current_view()->get_VIEW() );
570
571         // set the opengl state to known default values
572         default_state->force();
573
574         // update fog params if visibility has changed
575 #ifndef FG_OLD_WEATHER
576         thesky->set_visibility( WeatherDatabase->getWeatherVisibility() );
577 #else
578         thesky->set_visibility( current_weather.get_visibility() );
579 #endif
580
581         thesky->modify_vis( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
582                             ( global_multi_loop * 
583                               fgGetInt("/sim/speed-up") ) /
584                             (double)fgGetInt("/sim/model-hz") );
585
586         double actual_visibility = thesky->get_visibility();
587         // cout << "actual visibility = " << actual_visibility << endl;
588
589         if ( actual_visibility != last_visibility ) {
590             last_visibility = actual_visibility;
591
592             // cout << "----> updating fog params" << endl;
593                 
594             // for GL_FOG_EXP
595             fog_exp_density = -log(0.01) / actual_visibility;
596     
597             // for GL_FOG_EXP2
598             fog_exp2_density = sqrt( -log(0.01) ) / actual_visibility;
599             fog_exp2_punch_through = sqrt( -log(0.01) ) / 
600                 ( actual_visibility * 1.5 );
601         }
602
603         // Set correct opengl fog density
604         glFogf (GL_FOG_DENSITY, fog_exp2_density);
605
606         // update the sky dome
607         if ( fgGetBool("/sim/rendering/skyblend") ) {
608             /* cout << "thesky->repaint() sky_color = "
609                  << cur_light_params.sky_color[0] << " "
610                  << cur_light_params.sky_color[1] << " "
611                  << cur_light_params.sky_color[2] << " "
612                  << cur_light_params.sky_color[3] << endl;
613             cout << "    fog = "
614                  << cur_light_params.fog_color[0] << " "
615                  << cur_light_params.fog_color[1] << " "
616                  << cur_light_params.fog_color[2] << " "
617                  << cur_light_params.fog_color[3] << endl;
618             cout << "    sun_angle = " << cur_light_params.sun_angle
619                  << "    moon_angle = " << cur_light_params.moon_angle
620                  << endl; */
621             thesky->repaint( cur_light_params.sky_color,
622                              cur_light_params.adj_fog_color,
623                              cur_light_params.sun_angle,
624                              cur_light_params.moon_angle,
625                              globals->get_ephem()->getNumPlanets(),
626                              globals->get_ephem()->getPlanets(),
627                              globals->get_ephem()->getNumStars(),
628                              globals->get_ephem()->getStars() );
629  
630             /* cout << "thesky->reposition( view_pos = " << view_pos[0] << " "
631                  << view_pos[1] << " " << view_pos[2] << endl;
632             cout << "    zero_elev = " << zero_elev[0] << " "
633                  << zero_elev[1] << " " << zero_elev[2]
634                  << " lon = " << cur_fdm_state->get_Longitude()
635                  << " lat = " << cur_fdm_state->get_Latitude() << endl;
636             cout << "    sun_rot = " << cur_light_params.sun_rotation
637                  << " gst = " << SGTime::cur_time_params->getGst() << endl;
638             cout << "    sun ra = " << globals->get_ephem()->getSunRightAscension()
639                  << " sun dec = " << globals->get_ephem()->getSunDeclination() 
640                  << " moon ra = " << globals->get_ephem()->getMoonRightAscension()
641                  << " moon dec = " << globals->get_ephem()->getMoonDeclination() << endl; */
642
643             thesky->reposition( globals->get_current_view()->get_view_pos(),
644                                 globals->get_current_view()->get_zero_elev(),
645                                 globals->get_current_view()->get_world_up(),
646                                 cur_fdm_state->get_Longitude(),
647                                 cur_fdm_state->get_Latitude(),
648                                 cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
649                                 cur_light_params.sun_rotation,
650                                 globals->get_time_params()->getGst(),
651                                 globals->get_ephem()->getSunRightAscension(),
652                                 globals->get_ephem()->getSunDeclination(),
653                                 50000.0,
654                                 globals->get_ephem()->getMoonRightAscension(),
655                                 globals->get_ephem()->getMoonDeclination(),
656                                 50000.0 );
657         }
658
659         glEnable( GL_DEPTH_TEST );
660         if ( fgGetString("/sim/rendering/fog") != (string)"disabled" ) {
661             glEnable( GL_FOG );
662             glFogi( GL_FOG_MODE, GL_EXP2 );
663             glFogfv( GL_FOG_COLOR, l->adj_fog_color );
664         }
665
666         // set sun/lighting parameters
667         ssgGetLight( 0 ) -> setPosition( l->sun_vec );
668
669         // GL_LIGHT_MODEL_AMBIENT has a default non-zero value so if
670         // we only update GL_AMBIENT for our lights we will never get
671         // a completely dark scene.  So, we set GL_LIGHT_MODEL_AMBIENT
672         // explicitely to black.
673         GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
674         GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
675         glLightModelfv( GL_LIGHT_MODEL_AMBIENT, black );
676
677         ssgGetLight( 0 ) -> setColour( GL_AMBIENT, l->scene_ambient );
678         ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
679         // ssgGetLight( 0 ) -> setColour( GL_SPECULAR, l->scene_white );
680
681         // texture parameters
682         // glEnable( GL_TEXTURE_2D );
683         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
684         glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
685
686         // glMatrixMode( GL_PROJECTION );
687         // glLoadIdentity();
688         float fov = globals->get_current_view()->get_fov();
689         ssgSetFOV(fov, fov * globals->get_current_view()->get_fov_ratio());
690
691         double agl = current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER
692             - scenery.cur_elev;
693
694         // SG_LOG( SG_ALL, SG_INFO, "visibility is " 
695         //         << current_weather.get_visibility() );
696             
697         if ( agl > 10.0 ) {
698             ssgSetNearFar( 10.0f, 120000.0f );
699         } else {
700             ssgSetNearFar( 0.5f, 120000.0f );
701         }
702
703         if ( globals->get_viewmgr()->get_current() == 0 ) {
704             // disable aircraft model
705             acmodel_selector->select(0);
706         } else { 
707             // enable aircraft model and set up its position and orientation
708             acmodel_selector->select(1);
709
710             FGViewerRPH *pilot_view =
711                 (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
712
713             sgMat4 sgTRANS;
714             sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
715
716             sgVec3 ownship_up;
717             sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
718
719             sgMat4 sgROT;
720             sgMakeRotMat4( sgROT, -90.0, ownship_up );
721
722             // sgMat4 sgTMP;
723             // sgMat4 sgTUX;
724             // sgMultMat4( sgTMP, sgROT, pilot_view.VIEW_ROT );
725             // sgMultMat4( sgTUX, sgTMP, sgTRANS );
726
727             // sgTUX = ( sgROT * pilot_view.VIEW_ROT ) * sgTRANS
728             sgMat4 sgTUX;
729             sgCopyMat4( sgTUX, sgROT );
730             sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
731             sgPostMultMat4( sgTUX, sgTRANS );
732         
733             sgCoord tuxpos;
734             sgSetCoord( &tuxpos, sgTUX );
735             acmodel_pos->setTransform( &tuxpos );
736
737             // set up moving parts
738             if (flaps_selector != NULL) {
739                 flaps_selector->select( (globals->get_controls()->get_flaps() > 0.5f) ? 1 : 2 );
740             }
741
742             if (prop_selector != NULL) {
743               int propsel_mask = 0;
744               double rpm = fgGetDouble("/engines/engine[0]/rpm");
745               for (int i = 0; i < acmodel_npropsettings; i++) {
746                 if (rpm >= acmodel_proprpms[i][0] &&
747                     rpm <= acmodel_proprpms[i][1]) {
748                   propsel_mask |= 1 << i;
749                 }
750               }
751               prop_selector->select(propsel_mask);
752             }
753         }
754
755         // $$$ begin - added VS Renganthan 17 Oct 2K
756         fgUpdateDCS();
757         // $$$ end - added VS Renganthan 17 Oct 2K
758
759 # ifdef FG_NETWORK_OLK
760         if ( fgGetBool("/sim/networking/network-olk") ) {
761             sgCoord fgdpos;
762             other = head->next;             /* put listpointer to start  */
763             while ( other != tail) {        /* display all except myself */
764                 if ( strcmp( other->ipadr, fgd_mcp_ip) != 0) {
765                     other->fgd_sel->select(1);
766                     sgSetCoord( &fgdpos, other->sgFGD_COORD );
767                     other->fgd_pos->setTransform( &fgdpos );
768                 }
769                 other = other->next;
770             }
771
772             // fgd_sel->select(1);
773             // sgCopyMat4( sgTUX, current_view.sgVIEW);
774             // sgCoord fgdpos;
775             // sgSetCoord( &fgdpos, sgFGD_VIEW );
776             // fgd_pos->setTransform( &fgdpos);
777         }
778 # endif
779
780         // position tile nodes and update range selectors
781         global_tile_mgr.prep_ssg_nodes();
782
783         if ( fgGetBool("/sim/rendering/skyblend") ) {
784             // draw the sky backdrop
785
786             // we need a white diffuse light for the phase of the moon
787             ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, white );
788
789             thesky->preDraw();
790
791             // return to the desired diffuse color
792             ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
793         }
794
795         // draw the ssg scene
796         glEnable( GL_DEPTH_TEST );
797         ssgCullAndDraw( scene );
798
799         // change state for lighting here
800
801         // draw lighting
802         // Set punch through fog density
803         glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
804
805 #ifdef FG_EXPERIMENTAL_LIGHTING
806         // Enable states for drawing points with GL_extension
807         if (glutExtensionSupported("GL_EXT_point_parameters")) {
808             glEnable(GL_POINT_SMOOTH);
809             float quadratic[3] = {1.0, 0.01, 0.0001};
810             // get the address of our OpenGL extensions
811 #if !defined(sgi)
812             glPointParameterfEXT = (PFNGLPOINTPARAMETERFEXTPROC) 
813                 wglGetProcAddress("glPointParameterfEXT");
814             glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC) 
815                 wglGetProcAddress("glPointParameterfvEXT");
816 #endif
817             // makes the points fade as they move away
818             glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, quadratic);
819             glPointParameterfEXT(GL_POINT_SIZE_MIN_EXT, 1.0); 
820             glPointSize(4.0);
821
822             // Enable states for drawing runway lights with spherical mapping
823             glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
824             glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
825             glEnable(GL_TEXTURE_GEN_S);
826             glEnable(GL_TEXTURE_GEN_T);
827
828             //Maybe this is not the best way, but it works !!
829             glPolygonMode(GL_FRONT, GL_POINT);
830             glCullFace(GL_BACK);
831             glEnable(GL_CULL_FACE);
832         }
833
834         glDisable( GL_LIGHTING );
835         // blending function for runway lights
836         glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
837         glEnable(GL_BLEND);
838 #endif
839
840         ssgCullAndDraw( lighting );
841
842 #ifdef FG_EXPERIMENTAL_LIGHTING
843         if (glutExtensionSupported("GL_EXT_point_parameters")) {
844             // Disable states used for runway lighting
845             glPolygonMode(GL_FRONT, GL_FILL);
846
847             glDisable(GL_TEXTURE_GEN_S);
848             glDisable(GL_TEXTURE_GEN_T);
849             glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT,
850                                   default_attenuation);
851         }
852
853         glPointSize(1.0);
854 #endif
855
856         if ( fgGetBool("/sim/rendering/skyblend") ) {
857             // draw the sky cloud layers
858             thesky->postDraw( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER );
859         }
860
861         // display HUD && Panel
862         glDisable( GL_FOG );
863         glDisable( GL_DEPTH_TEST );
864         // glDisable( GL_CULL_FACE );
865         // glDisable( GL_TEXTURE_2D );
866
867         // update the input subsystem
868         current_input.update();
869
870         // update the controls subsystem
871         globals->get_controls()->update();
872
873         hud_and_panel->apply();
874         fgCockpitUpdate();
875
876         // update the panel subsystem
877         if (current_panel != 0)
878           current_panel->update();
879
880         // We can do translucent menus, so why not. :-)
881         menus->apply();
882         glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
883         puDisplay();
884         // glDisable ( GL_BLEND ) ;
885
886         // glEnable( GL_FOG );
887     }
888
889     glutSwapBuffers();
890 }
891
892
893 // Update internal time dependent calculations (i.e. flight model)
894 void fgUpdateTimeDepCalcs() {
895     static bool inited = false;
896
897     fgLIGHT *l = &cur_light_params;
898     int i;
899
900     long multi_loop = 1;
901
902     if ( !globals->get_freeze() && !initial_freeze ) {
903         // conceptually, this could be done for each fdm instance ...
904
905         if ( !inited ) {
906             cur_fdm_state->stamp();
907             inited = true;
908         }
909
910         SGTimeStamp current;
911         current.stamp();
912         long elapsed = current - cur_fdm_state->get_time_stamp();
913         cur_fdm_state->set_time_stamp( current );
914         elapsed += cur_fdm_state->get_remainder();
915         // cout << "elapsed = " << elapsed << endl;
916         // cout << "dt = " << cur_fdm_state->get_delta_t() << endl;
917         multi_loop = (long)(((double)elapsed * 0.000001) /
918                                cur_fdm_state->get_delta_t() );
919         cur_fdm_state->set_multi_loop( multi_loop );
920         long remainder = elapsed - (long)( (multi_loop*1000000) *
921                                      cur_fdm_state->get_delta_t() );
922         cur_fdm_state->set_remainder( remainder );
923         // cout << "remainder = " << remainder << endl;
924
925         // chop max interations to something reasonable if the sim was
926         // delayed for an excesive amount of time
927         if ( multi_loop > 2.0 / cur_fdm_state->get_delta_t() ) {
928             multi_loop = (int)(2.0 / cur_fdm_state->get_delta_t());
929             cur_fdm_state->set_remainder( 0 );
930         }
931
932         // cout << "multi_loop = " << multi_loop << endl;
933         for ( i = 0; i < multi_loop * fgGetInt("/sim/speed-up"); ++i ) {
934             // run Autopilot system
935             current_autopilot->run();
936
937             // update autopilot
938             cur_fdm_state->update( 1 );
939         }
940         FGSteam::update( multi_loop * fgGetInt("/sim/speed-up") );
941     } else {
942         cur_fdm_state->update( 0 );
943         FGSteam::update( 0 );
944
945         //if ( global_tile_mgr.queue_size() == 0 ) {
946             initial_freeze = false;
947             //}
948     }
949
950     if ( fgGetString("/sim/view-mode") == "pilot" ) {
951         cur_view_fdm = *cur_fdm_state;
952         // do nothing
953     }
954
955     // update the view angle
956     FGViewer *v = globals->get_current_view();
957     for ( i = 0; i < multi_loop; i++ ) {
958         if ( fabs(v->get_goal_view_offset() - v->get_view_offset()) < 0.05 ) {
959             v->set_view_offset( v->get_goal_view_offset() );
960             break;
961         } else {
962             // move current_view.view_offset towards
963             // current_view.goal_view_offset
964             if ( v->get_goal_view_offset() > v->get_view_offset() )
965             {
966                 if ( v->get_goal_view_offset() - v->get_view_offset() < SGD_PI ){
967                     v->inc_view_offset( 0.01 );
968                 } else {
969                     v->inc_view_offset( -0.01 );
970                 }
971             } else {
972                 if ( v->get_view_offset() - v->get_goal_view_offset() < SGD_PI ){
973                     v->inc_view_offset( -0.01 );
974                 } else {
975                     v->inc_view_offset( 0.01 );
976                 }
977             }
978             if ( v->get_view_offset() > SGD_2PI ) {
979                 v->inc_view_offset( -SGD_2PI );
980             } else if ( v->get_view_offset() < 0 ) {
981                 v->inc_view_offset( SGD_2PI );
982             }
983         }
984     }
985
986     double tmp = -(l->sun_rotation + SGD_PI) 
987         - (cur_fdm_state->get_Psi() -
988            globals->get_current_view()->get_view_offset() );
989     while ( tmp < 0.0 ) {
990         tmp += SGD_2PI;
991     }
992     while ( tmp > SGD_2PI ) {
993         tmp -= SGD_2PI;
994     }
995     /* printf("Psi = %.2f, viewoffset = %.2f sunrot = %.2f rottosun = %.2f\n",
996            FG_Psi * SGD_RADIANS_TO_DEGREES, current_view.view_offset * SGD_RADIANS_TO_DEGREES, 
997            -(l->sun_rotation+SGD_PI) * SGD_RADIANS_TO_DEGREES, tmp * SGD_RADIANS_TO_DEGREES); */
998     l->UpdateAdjFog();
999
1000     // Update solar system
1001     globals->get_ephem()->update( globals->get_time_params()->getMjd(),
1002                                   globals->get_time_params()->getLst(),
1003                                   cur_fdm_state->get_Latitude() );
1004
1005     // Update radio stack model
1006     current_radiostack->update();
1007 }
1008
1009
1010 void fgInitTimeDepCalcs( void ) {
1011     // initialize timer
1012
1013     // #ifdef HAVE_SETITIMER
1014     //   fgTimerInit( 1.0 / fgGetInt("/sim/model-hz"), 
1015     //                fgUpdateTimeDepCalcs );
1016     // #endif HAVE_SETITIMER
1017 }
1018
1019
1020 static const double alt_adjust_ft = 3.758099;
1021 static const double alt_adjust_m = alt_adjust_ft * SG_FEET_TO_METER;
1022
1023
1024 // What should we do when we have nothing else to do?  Let's get ready
1025 // for the next move and update the display?
1026 static void fgMainLoop( void ) {
1027     static long remainder = 0;
1028     long elapsed;
1029 #ifdef FANCY_FRAME_COUNTER
1030     int i;
1031     double accum;
1032 #else
1033     static time_t last_time = 0;
1034     static int frames = 0;
1035 #endif // FANCY_FRAME_COUNTER
1036
1037     SGTime *t = globals->get_time_params();
1038
1039     SG_LOG( SG_ALL, SG_DEBUG, "Running Main Loop");
1040     SG_LOG( SG_ALL, SG_DEBUG, "======= ==== ====");
1041
1042 #ifdef FG_NETWORK_OLK
1043     if ( fgGetBool("/sim/networking/network-olk") ) {
1044         if ( net_is_registered == 0 ) {      // We first have to reg. to fgd
1045             // printf("FGD: Netupdate\n");
1046             fgd_send_com( "A", FGFS_host);   // Send Mat4 data
1047             fgd_send_com( "B", FGFS_host);   // Recv Mat4 data
1048         }
1049     }
1050 #endif
1051
1052 #if defined( ENABLE_PLIB_JOYSTICK )
1053     // Read joystick and update control settings
1054     // if ( fgGetString("/sim/control-mode") == "joystick" )
1055     // {
1056     //    fgJoystickRead();
1057     // }
1058 #elif defined( ENABLE_GLUT_JOYSTICK )
1059     // Glut joystick support works by feeding a joystick handler
1060     // function to glut.  This is taken care of once in the joystick
1061     // init routine and we don't have to worry about it again.
1062 #endif
1063
1064 #ifdef FG_OLD_WEATHER
1065     current_weather.Update();
1066 #endif
1067
1068     // Fix elevation.  I'm just sticking this here for now, it should
1069     // probably move eventually
1070
1071     /* printf("Before - ground = %.2f  runway = %.2f  alt = %.2f\n",
1072            scenery.cur_elev,
1073            cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
1074            cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
1075
1076     if ( scenery.cur_elev > -9990 ) {
1077         if ( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER < 
1078              (scenery.cur_elev + alt_adjust_m - 3.0) ) {
1079             // now set aircraft altitude above ground
1080             printf("(*) Current Altitude = %.2f < %.2f forcing to %.2f\n", 
1081                    cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
1082                    scenery.cur_elev + alt_adjust_m - 3.0,
1083                    scenery.cur_elev + alt_adjust_m );
1084             fgFDMForceAltitude( fgGetString("/sim/flight-model"), 
1085                                 scenery.cur_elev + alt_adjust_m );
1086
1087             SG_LOG( SG_ALL, SG_DEBUG, 
1088                     "<*> resetting altitude to " 
1089                     << cur_fdm_state->get_Altitude() * SG_FEET_TO_METER
1090                     << " meters" );
1091         }
1092     }
1093
1094     /* printf("Adjustment - ground = %.2f  runway = %.2f  alt = %.2f\n",
1095            scenery.cur_elev,
1096            cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
1097            cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
1098
1099     // cout << "Warp = " << globals->get_warp() << endl;
1100
1101     // update "time"
1102     if ( globals->get_warp_delta() != 0 ) {
1103         globals->inc_warp( globals->get_warp_delta() );
1104     }
1105
1106     t->update( cur_fdm_state->get_Longitude(),
1107                cur_fdm_state->get_Latitude(),
1108                globals->get_warp() );
1109
1110     if ( globals->get_warp_delta() != 0 ) {
1111         fgUpdateSkyAndLightingParams();
1112     }
1113
1114     // update magvar model
1115     globals->get_mag()->update( cur_fdm_state->get_Longitude(),
1116                                 cur_fdm_state->get_Latitude(),
1117                                 cur_fdm_state->get_Altitude()* SG_FEET_TO_METER,
1118                                 globals->get_time_params()->getJD() );
1119
1120     // Get elapsed time (in usec) for this past frame
1121     elapsed = fgGetTimeInterval();
1122     SG_LOG( SG_ALL, SG_DEBUG, 
1123             "Elapsed time interval is = " << elapsed 
1124             << ", previous remainder is = " << remainder );
1125
1126     // Calculate frame rate average
1127 #ifdef FANCY_FRAME_COUNTER
1128     /* old fps calculation */
1129     if ( elapsed > 0 ) {
1130         double tmp;
1131         accum = 0.0;
1132         for ( i = FG_FRAME_RATE_HISTORY - 2; i >= 0; i-- ) {
1133             tmp = general.get_frame(i);
1134             accum += tmp;
1135             // printf("frame[%d] = %.2f\n", i, g->frames[i]);
1136             general.set_frame(i+1,tmp);
1137         }
1138         tmp = 1000000.0 / (float)elapsed;
1139         general.set_frame(0,tmp);
1140         // printf("frame[0] = %.2f\n", general.frames[0]);
1141         accum += tmp;
1142         general.set_frame_rate(accum / (float)FG_FRAME_RATE_HISTORY);
1143         // printf("ave = %.2f\n", general.frame_rate);
1144     }
1145 #else
1146     if ( (t->get_cur_time() != last_time) && (last_time > 0) ) {
1147         general.set_frame_rate( frames );
1148         SG_LOG( SG_ALL, SG_DEBUG, 
1149                 "--> Frame rate is = " << general.get_frame_rate() );
1150         frames = 0;
1151     }
1152     last_time = t->get_cur_time();
1153     ++frames;
1154 #endif
1155
1156     // Run flight model
1157
1158     // Calculate model iterations needed for next frame
1159     elapsed += remainder;
1160
1161     global_multi_loop = (long)(((double)elapsed * 0.000001) * 
1162                               fgGetInt("/sim/model-hz"));
1163     remainder = elapsed - ( (global_multi_loop*1000000) / 
1164                             fgGetInt("/sim/model-hz") );
1165     SG_LOG( SG_ALL, SG_DEBUG, 
1166             "Model iterations needed = " << global_multi_loop
1167             << ", new remainder = " << remainder );
1168         
1169     // chop max interations to something reasonable if the sim was
1170     // delayed for an excesive amount of time
1171     if ( global_multi_loop > 2.0 * fgGetInt("/sim/model-hz") ) {
1172         global_multi_loop = (int)(2.0 * fgGetInt("/sim/model-hz") );
1173         remainder = 0;
1174     }
1175
1176     // flight model
1177     if ( global_multi_loop > 0 ) {
1178         fgUpdateTimeDepCalcs();
1179     } else {
1180         SG_LOG( SG_ALL, SG_DEBUG, 
1181                 "Elapsed time is zero ... we're zinging" );
1182     }
1183
1184 #if ! defined( macintosh )
1185     // Do any I/O channel work that might need to be done
1186     fgIOProcess();
1187 #endif
1188
1189     // see if we need to load any new scenery tiles
1190     global_tile_mgr.update( cur_fdm_state->get_Longitude()
1191                             * SGD_RADIANS_TO_DEGREES,
1192                             cur_fdm_state->get_Latitude()
1193                             * SGD_RADIANS_TO_DEGREES );
1194
1195     // see if we need to load any deferred-load textures
1196     material_lib.load_next_deferred();
1197
1198     // Process/manage pending events
1199     global_events.Process();
1200
1201     // Run audio scheduler
1202 #ifdef ENABLE_AUDIO_SUPPORT
1203     static bool bCranking;
1204     if ( fgGetBool("/sim/sound") && globals->get_soundmgr()->is_working() ) {
1205         if ( fgGetString("/sim/aircraft") == "c172" ) {
1206             if(fgGetBool("/engines/engine[0]/running")) {
1207                 // pitch corresponds to rpm
1208                 // volume corresponds to manifold pressure
1209
1210                 // cout << "AUDIO working = "
1211                 //      << globals->get_soundmgr()->is_working() << endl;
1212
1213                 double rpm_factor;
1214                 if ( cur_fdm_state->get_engine(0) != NULL ) {
1215                     rpm_factor = cur_fdm_state->get_engine(0)->get_RPM() / 2500.0;
1216                 } else {
1217                     rpm_factor = 1.0;
1218                 }
1219                 // cout << "rpm = " << cur_fdm_state->get_engine(0)->get_RPM()
1220                 //      << endl;
1221
1222                 double pitch = 0.3 + rpm_factor * 3.0;
1223         
1224                 // don't run at absurdly slow rates -- not realistic
1225                 // and sounds bad to boot.  :-)
1226                 if (pitch < 0.7) { pitch = 0.7; }
1227                 if (pitch > 5.0) { pitch = 5.0; }
1228
1229                 double mp_factor;
1230                 if ( cur_fdm_state->get_engine(0) != NULL ) {
1231                     mp_factor = cur_fdm_state->get_engine(0)->get_Manifold_Pressure() / 100;
1232                 } else {
1233                     mp_factor = 0.3;
1234                 }
1235                 /* cout << "mp = " 
1236                     << cur_fdm_state->get_engine(0)->get_Manifold_Pressure()
1237                     << endl; */
1238
1239                 double volume = 0.15 + mp_factor / 2.0;
1240
1241                 if ( volume < 0.15 ) { volume = 0.15; }
1242                 if ( volume > 0.5 ) { volume = 0.5; }
1243                 // cout << "volume = " << volume << endl;
1244
1245                 s1->set_pitch( pitch );
1246                 s1->set_volume( volume );
1247             } else {
1248                 s1->set_pitch(0.0);
1249                 s1->set_volume(0.0);
1250             }
1251             if(fgGetBool("/engines/engine[0]/cranking")) {
1252                 if(!bCranking) {
1253                     globals->get_soundmgr()->play_looped("cranking");
1254                     bCranking = true;
1255                 }
1256             } else {
1257                 if(bCranking) {
1258                     globals->get_soundmgr()->stop("cranking");
1259                     bCranking = false;
1260                 }
1261             }
1262         } else {    // Not C172
1263             double param
1264                 = globals->get_controls()->get_throttle( 0 ) * 2.0 + 1.0;
1265             s1->set_pitch( param );
1266             s1->set_volume( param );
1267         }
1268
1269         globals->get_soundmgr()->update();
1270     }
1271 #endif
1272
1273     // redraw display
1274     fgRenderFrame();
1275
1276     SG_LOG( SG_ALL, SG_DEBUG, "" );
1277 }
1278
1279
1280 // This is the top level master main function that is registered as
1281 // our idle funciton
1282 //
1283
1284 // The first few passes take care of initialization things (a couple
1285 // per pass) and once everything has been initialized fgMainLoop from
1286 // then on.
1287
1288 static void fgIdleFunction ( void ) {
1289     // printf("idle state == %d\n", idle_state);
1290
1291     if ( idle_state == 0 ) {
1292         // Initialize the splash screen right away
1293         if ( fgGetBool("/sim/startup/splash-screen") ) {
1294             fgSplashInit();
1295         }
1296         
1297         idle_state++;
1298     } else if ( idle_state == 1 ) {
1299         // Initialize audio support
1300 #ifdef ENABLE_AUDIO_SUPPORT
1301
1302         // Start the intro music
1303 #if !defined(WIN32)
1304         if ( fgGetBool("/sim/startup/intro-music") ) {
1305             SGPath mp3file( globals->get_fg_root() );
1306             mp3file.append( "Sounds/intro.mp3" );
1307
1308             SG_LOG( SG_GENERAL, SG_INFO, 
1309                     "Starting intro music: " << mp3file.str() );
1310
1311             string command = "mpg123 " + mp3file.str() + "> /dev/null 2>&1";
1312             system ( command.c_str() );
1313         }
1314 #endif // !WIN32
1315
1316         FGSoundMgr *soundmgr = new FGSoundMgr;
1317         globals->set_soundmgr( soundmgr );
1318
1319         if ( fgGetBool("/sim/sound") ) {
1320             globals->get_soundmgr()->init();
1321
1322             s1 = new FGSimpleSound( fgGetString("/sim/sounds/engine",
1323                                                 "Sounds/wasp.wav") );
1324             globals->get_soundmgr()->add( s1, "engine loop" );
1325             globals->get_soundmgr()->play_looped( "engine loop" );
1326             SG_LOG( SG_GENERAL, SG_INFO,
1327                     "Rate = " << s1->get_sample()->getRate()
1328                     << "  Bps = " << s1->get_sample()->getBps()
1329                     << "  Stereo = " << s1->get_sample()->getStereo() );
1330
1331             // s2 = new FGSimpleSound( "Sounds/corflaps.wav" );
1332             // s2->set_volume( 0.3 );
1333             // globals->get_soundmgr()->add( s2, "flaps" );
1334             s2 = new FGSimpleSound( fgGetString("/sim/sounds/engine",
1335                                                 "Sounds/cranking.wav") );
1336             globals->get_soundmgr()->add( s2, "cranking" );
1337             s2->set_pitch(1.5);
1338             s2->set_volume(0.25);
1339         }
1340 #endif
1341
1342         idle_state++;
1343     } else if ( idle_state == 2 ) {
1344         // These are a few miscellaneous things that aren't really
1345         // "subsystems" but still need to be initialized.
1346
1347 #ifdef USE_GLIDE
1348         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1349             grTexLodBiasValue ( GR_TMU0, 1.0 ) ;
1350         }
1351 #endif
1352
1353         idle_state++;
1354     } else if ( idle_state == 3 ) {
1355         // This is the top level init routine which calls all the
1356         // other subsystem initialization routines.  If you are adding
1357         // a subsystem to flightgear, its initialization call should
1358         // located in this routine.
1359         if( !fgInitSubsystems()) {
1360             SG_LOG( SG_GENERAL, SG_ALERT,
1361                     "Subsystem initializations failed ..." );
1362             exit(-1);
1363         }
1364
1365         idle_state++;
1366     } else if ( idle_state == 4 ) {
1367         // setup OpenGL view parameters
1368         fgInitVisuals();
1369
1370         idle_state++;
1371     } else if ( idle_state == 5 ) {
1372
1373         idle_state++;
1374     } else if ( idle_state == 6 ) {
1375         // sleep(1);
1376         idle_state = 1000;
1377
1378         cout << "Panel visible = " << fgPanelVisible() << endl;
1379         fgReshape( fgGetInt("/sim/startup/xsize"),
1380                    fgGetInt("/sim/startup/ysize") );
1381     } 
1382
1383     if ( idle_state == 1000 ) {
1384         // We've finished all our initialization steps, from now on we
1385         // run the main loop.
1386
1387         fgMainLoop();
1388     } else {
1389         if ( fgGetBool("/sim/startup/splash-screen") ) {
1390             fgSplashUpdate(0.0);
1391         }
1392     }
1393 }
1394
1395 // options.cxx needs to see this for toggle_panel()
1396 // Handle new window size or exposure
1397 void fgReshape( int width, int height ) {
1398     int view_h;
1399
1400     if ( fgPanelVisible() && idle_state == 1000 ) {
1401         view_h = (int)(height * (current_panel->getViewHeight() -
1402                                  current_panel->getYOffset()) / 768.0);
1403     } else {
1404         view_h = height;
1405     }
1406
1407     // for all views
1408     for ( int i = 0; i < globals->get_viewmgr()->size(); ++i ) {
1409         globals->get_viewmgr()->get_view(i)->
1410             set_aspect_ratio((float)view_h / (float)width);
1411     }
1412
1413     glViewport( 0, (GLint)(height - view_h), (GLint)(width), (GLint)(view_h) );
1414
1415     fgSetInt("/sim/startup/xsize", width);
1416     fgSetInt("/sim/startup/ysize", height);
1417
1418     float fov = globals->get_current_view()->get_fov();
1419     ssgSetFOV(fov, fov * globals->get_current_view()->get_fov_ratio());
1420
1421     fgHUDReshape();
1422 }
1423
1424
1425 // Initialize GLUT and define a main window
1426 int fgGlutInit( int *argc, char **argv ) {
1427
1428 #if !defined( macintosh )
1429     // GLUT will extract all glut specific options so later on we only
1430     // need wory about our own.
1431     glutInit(argc, argv);
1432 #endif
1433
1434     // Define Display Parameters
1435     glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
1436
1437     SG_LOG( SG_GENERAL, SG_INFO, "Opening a window: " <<
1438             fgGetInt("/sim/startup/xsize") << "x"
1439             << fgGetInt("/sim/startup/ysize") );
1440
1441     // Define initial window size
1442     glutInitWindowSize( fgGetInt("/sim/startup/xsize"),
1443                         fgGetInt("/sim/startup/ysize") );
1444
1445     // Initialize windows
1446     if ( !fgGetBool("/sim/startup/game-mode")) {
1447         // Open the regular window
1448         glutCreateWindow("FlightGear");
1449 #ifndef GLUT_WRONG_VERSION
1450     } else {
1451         // Open the cool new 'game mode' window
1452         char game_mode_str[256];
1453         sprintf( game_mode_str, "width=%d height=%d bpp=%d",
1454                  fgGetInt("/sim/startup/xsize"),
1455                  fgGetInt("/sim/startup/ysize"),
1456                  fgGetInt("/sim/rendering/bits-per-pixel"));
1457
1458         SG_LOG( SG_GENERAL, SG_INFO, 
1459                 "game mode params = " << game_mode_str );
1460         glutGameModeString( game_mode_str );
1461         glutEnterGameMode();
1462 #endif
1463     }
1464
1465     // This seems to be the absolute earliest in the init sequence
1466     // that these calls will return valid info.  Too bad it's after
1467     // we've already created and sized out window. :-(
1468     general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
1469     general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
1470     general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
1471     SG_LOG( SG_GENERAL, SG_INFO, general.get_glRenderer() );
1472
1473     GLint tmp;
1474     glGetIntegerv( GL_MAX_TEXTURE_SIZE, &tmp );
1475     general.set_glMaxTexSize( tmp );
1476     SG_LOG ( SG_GENERAL, SG_INFO, "Max texture size = " << tmp );
1477
1478     glGetIntegerv( GL_DEPTH_BITS, &tmp );
1479     general.set_glDepthBits( tmp );
1480     SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp );
1481
1482     return 1;
1483 }
1484
1485
1486 // Initialize GLUT event handlers
1487 int fgGlutInitEvents( void ) {
1488     // call fgReshape() on window resizes
1489     glutReshapeFunc( fgReshape );
1490
1491     // call GLUTkey() on keyboard event
1492     glutKeyboardFunc(GLUTkey);
1493     glutKeyboardUpFunc(GLUTkeyup);
1494     glutSpecialFunc(GLUTspecialkey);
1495     glutSpecialUpFunc(GLUTspecialkeyup);
1496
1497     // call guiMouseFunc() whenever our little rodent is used
1498     glutMouseFunc ( guiMouseFunc );
1499     glutMotionFunc (guiMotionFunc );
1500     glutPassiveMotionFunc (guiMotionFunc );
1501
1502     // call fgMainLoop() whenever there is
1503     // nothing else to do
1504     glutIdleFunc( fgIdleFunction );
1505
1506     // draw the scene
1507     glutDisplayFunc( fgRenderFrame );
1508
1509     return(1);
1510 }
1511
1512
1513 // Main loop
1514 int mainLoop( int argc, char **argv ) {
1515
1516 #if defined( macintosh )
1517     freopen ("stdout.txt", "w", stdout );
1518     freopen ("stderr.txt", "w", stderr );
1519     argc = ccommand( &argv );
1520 #endif
1521
1522     // set default log levels
1523     sglog().setLogLevels( SG_ALL, SG_INFO );
1524
1525     string version;
1526 #ifdef FLIGHTGEAR_VERSION
1527     version = FLIGHTGEAR_VERSION;
1528 #else
1529     version = "unknown version";
1530 #endif
1531     SG_LOG( SG_GENERAL, SG_INFO, "FlightGear:  Version "
1532             << version << endl );
1533
1534     // Allocate global data structures.  This needs to happen before
1535     // we parse command line options
1536
1537     globals = new FGGlobals;
1538
1539     // seed the random number generater
1540     sg_srandom_time();
1541
1542     SGRoute *route = new SGRoute;
1543     globals->set_route( route );
1544
1545     FGControls *controls = new FGControls;
1546     globals->set_controls( controls );
1547
1548     FGViewMgr *viewmgr = new FGViewMgr;
1549     globals->set_viewmgr( viewmgr );
1550
1551     FGViewerRPH *pv = new FGViewerRPH;
1552     globals->get_viewmgr()->add_view( pv );
1553
1554     FGViewerLookAt *chase = new FGViewerLookAt;
1555     globals->get_viewmgr()->add_view( chase );
1556
1557     string_list *col = new string_list;
1558     globals->set_channel_options_list( col );
1559
1560     // set current view to 0 (first) which is our main pilot view
1561     globals->set_current_view( globals->get_viewmgr()->get_view( 0 ) );
1562
1563     // Scan the config file(s) and command line options to see if
1564     // fg_root was specified (ignore all other options for now)
1565     fgInitFGRoot(argc, argv);
1566
1567     // Check for the correct base package version
1568     string base_version = fgBasePackageVersion();
1569     if ( !(base_version == "0.7.9") ) {
1570         SG_LOG( SG_GENERAL, SG_ALERT, "Base package check failed ... "
1571                 << "Found version " << base_version );
1572         SG_LOG( SG_GENERAL, SG_ALERT, "Please upgrade to version 0.7.9" );
1573         exit(-1);
1574     }
1575
1576     // Initialize the Aircraft directory to "" (UIUC)
1577     aircraft_dir = "";
1578
1579     // Load the configuration parameters
1580     if ( !fgInitConfig(argc, argv) ) {
1581         SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
1582         exit(-1);
1583     }
1584
1585     // Initialize the Window/Graphics environment.
1586     if( !fgGlutInit(&argc, argv) ) {
1587         SG_LOG( SG_GENERAL, SG_ALERT, "GLUT initialization failed ..." );
1588         exit(-1);
1589     }
1590
1591     // Initialize the various GLUT Event Handlers.
1592     if( !fgGlutInitEvents() ) {
1593         SG_LOG( SG_GENERAL, SG_ALERT, 
1594                 "GLUT event handler initialization failed ..." );
1595         exit(-1);
1596     }
1597
1598     // Initialize plib net interface
1599     netInit( &argc, argv );
1600
1601     // Initialize ssg (from plib).  Needs to come before we do any
1602     // other ssg stuff, but after opengl/glut has been initialized.
1603     ssgInit();
1604
1605     // Initialize the user interface (we need to do this before
1606     // passing off control to glut and before fgInitGeneral to get our
1607     // fonts !!!
1608     guiInit();
1609
1610 #ifdef GL_EXT_texture_lod_bias
1611     glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, -0.5 ) ;
1612 #endif
1613
1614 #if 0
1615 #ifdef GL_EXT_texture_filter_anisotropic
1616     float max_anisotropy;
1617     glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy );
1618     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
1619                      max_anisotropy );
1620     cout << "Max anisotropy = " << max_anisotropy << endl;
1621 #endif
1622 #endif
1623
1624     // set current_options lon/lat if an airport id is specified
1625     // cout << "3. airport_id = " << fgGetString("/sim/startup/airport-id") << endl;
1626     if ( fgGetString("/sim/startup/airport-id").length() ) {
1627         // fgSetPosFromAirportID( fgGetString("/sim/startup/airport-id") );
1628         fgSetPosFromAirportIDandHdg( fgGetString("/sim/startup/airport-id"),
1629                                      fgGetDouble("/orientation/heading-deg") );
1630     }
1631
1632     // Initialize time
1633     SGPath zone( globals->get_fg_root() );
1634     zone.append( "Timezone" );
1635     SGTime *t = new SGTime( fgGetDouble("/position/longitude-deg") * SGD_DEGREES_TO_RADIANS,
1636                             fgGetDouble("/position/latitude-deg") * SGD_DEGREES_TO_RADIANS,
1637                             zone.str() );
1638
1639     // Handle potential user specified time offsets
1640     time_t cur_time = t->get_cur_time();
1641     time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
1642     time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
1643     time_t aircraftLocalTime = 
1644         sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
1645
1646     // Okay, we now have six possible scenarios
1647     int offset = fgGetInt("/sim/startup/time-offset");
1648     const string &offset_type = fgGetString("/sim/startup/time-offset-type");
1649     if (offset_type == "system-offset") {
1650         globals->set_warp( offset );
1651     } else if (offset_type == "gmt-offset") {
1652         globals->set_warp( offset - (currGMT - systemLocalTime) );
1653     } else if (offset_type == "latitude-offset") {
1654         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) );
1655     } else if (offset_type == "system") {
1656         globals->set_warp( offset - cur_time );
1657     } else if (offset_type == "gmt") {
1658         globals->set_warp( offset - currGMT );
1659     } else if (offset_type == "latitude") {
1660         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) - 
1661                            cur_time ); 
1662     } else {
1663         SG_LOG( SG_GENERAL, SG_ALERT,
1664                 "Unsupported offset type " << offset_type );
1665         exit( -1 );
1666     }
1667
1668     SG_LOG( SG_GENERAL, SG_INFO, "After time init, warp = " 
1669             << globals->get_warp() );
1670
1671     globals->set_warp_delta( 0 );
1672
1673     t->update( 0.0, 0.0, globals->get_warp() );
1674
1675     globals->set_time_params( t );
1676
1677     // Do some quick general initializations
1678     if( !fgInitGeneral()) {
1679         SG_LOG( SG_GENERAL, SG_ALERT, 
1680                 "General initializations failed ..." );
1681         exit(-1);
1682     }
1683
1684     SGPath modelpath( globals->get_fg_root() );
1685     ssgModelPath( (char *)modelpath.c_str() );
1686   
1687     // Scene graph root
1688     scene = new ssgRoot;
1689     scene->setName( "Scene" );
1690
1691     lighting = new ssgRoot;
1692     lighting->setName( "Lighting" );
1693
1694     // Initialize the sky
1695     SGPath ephem_data_path( globals->get_fg_root() );
1696     ephem_data_path.append( "Astro" );
1697     SGEphemeris *ephem = new SGEphemeris( ephem_data_path.c_str() );
1698     ephem->update( globals->get_time_params()->getMjd(),
1699                    globals->get_time_params()->getLst(),
1700                    0.0 );
1701     globals->set_ephem( ephem );
1702
1703     thesky = new SGSky;
1704
1705     SGPath sky_tex_path( globals->get_fg_root() );
1706     sky_tex_path.append( "Textures" );
1707     sky_tex_path.append( "Sky" );
1708     thesky->texture_path( sky_tex_path.str() );
1709
1710     thesky->build( 550.0, 550.0,
1711                    globals->get_ephem()->getNumPlanets(), 
1712                    globals->get_ephem()->getPlanets(), 60000.0,
1713                    globals->get_ephem()->getNumStars(),
1714                    globals->get_ephem()->getStars(), 60000.0 );
1715
1716     if ( fgGetBool("/environment/clouds/status") ) {
1717         // thesky->add_cloud_layer( 2000.0, 200.0, 50.0, 40000.0,
1718         //                          SG_CLOUD_OVERCAST );
1719         thesky->add_cloud_layer( 2600.0, 200.0, 50.0, 40000.0,
1720                                  SG_CLOUD_MOSTLY_CLOUDY );
1721         // thesky->add_cloud_layer( 3000.0, 200.0, 50.0, 40000.0,
1722         //                          SG_CLOUD_MOSTLY_SUNNY );
1723         thesky->add_cloud_layer( 6000.0, 20.0, 10.0, 40000.0,
1724                                  SG_CLOUD_CIRRUS );
1725     }
1726
1727     // Initialize MagVar model
1728     SGMagVar *magvar = new SGMagVar();
1729     globals->set_mag( magvar );
1730
1731     // Terrain branch
1732     terrain = new ssgBranch;
1733     terrain->setName( "Terrain" );
1734     scene->addKid( terrain );
1735
1736     // Lighting
1737     ground = new ssgBranch;
1738     ground->setName( "Ground Lighting" );
1739     lighting->addKid( ground );
1740
1741     airport = new ssgBranch;
1742     airport->setName( "Airport Lighting" );
1743     lighting->addKid( airport );
1744
1745     // ADA
1746     fgLoadDCS();
1747     // ADA
1748
1749     // temporary visible aircraft "own ship"
1750     acmodel_selector = new ssgSelector;
1751     acmodel_pos = new ssgTransform;
1752
1753     ssgEntity *acmodel_obj = NULL;
1754     if (fgGetString("/sim/flight-model") == "ada") {
1755         // ada exteranl aircraft model loading
1756         if( !ship_pos[0]->getKid(0) ) {
1757             // fall back to default
1758             ssgEntity *acmodel_obj = ssgLoad( (char *)"glider.ac" );
1759             if( !acmodel_obj ) {
1760                 SG_LOG( SG_GENERAL, SG_ALERT, "FAILED to LOAD an AC model! ..." );
1761                 exit(-1);
1762             }
1763             acmodel_pos->addKid( acmodel_obj );
1764         } else {
1765             acmodel_obj = ship_pos[0]->getKid(0);
1766         }
1767     } else {
1768         // default aircraft model loading
1769
1770         // Get the model location, and load textures from the same
1771         // directory.  Use an absolute path for the model to avoid
1772         // incompatibilities in different versions of PLIB.
1773         string acmodel_path =
1774             fgGetString("/sim/model/path", "Models/Geometry/glider.ac");
1775         SGPath full_model = globals->get_fg_root();
1776         full_model.append(acmodel_path);
1777
1778         ssgTexturePath( (char *)full_model.dir().c_str() );
1779         acmodel_obj = ssgLoad( (char *)full_model.c_str() );
1780         if( !acmodel_obj ) {
1781             // fall back to default
1782             acmodel_obj = ssgLoad( (char *)"Models/Geometry/glider.ac" );
1783             if( !acmodel_obj ) {
1784                 SG_LOG( SG_GENERAL, SG_ALERT, "FAILED to LOAD an AC model! ..." );
1785                 exit(-1);
1786             }
1787         }
1788     }
1789
1790     // find moving parts (if this is an MDL model)
1791     flaps_selector = (ssgSelector*)fgFindNode( acmodel_obj, "FLAPS" );
1792     prop_selector  = (ssgSelector*)fgFindNode( acmodel_obj, "PROP"  );
1793
1794     acmodel_npropsettings = 0;
1795     if (prop_selector != NULL) {
1796       for (ssgEntity* kid = prop_selector->getKid(0); kid != NULL;
1797            kid = prop_selector->getNextKid()) {
1798         int prop_low, prop_high;
1799         if ( sscanf(kid->getName(), "PROP_%d_%d", 
1800                     &prop_low, &prop_high) == 2 ) {
1801           prop_low  = (int)((float)prop_low  * (5000.0f / 32767.0f));
1802           prop_high = (int)((float)prop_high * (5000.0f / 32767.0f));
1803           acmodel_proprpms[acmodel_npropsettings][0] = prop_low ;
1804           acmodel_proprpms[acmodel_npropsettings][1] = prop_high;
1805           acmodel_npropsettings++;
1806
1807           SG_LOG( SG_GENERAL, SG_INFO, "PROPELLER SETTING " << prop_low <<
1808                   " " << prop_high );
1809         }
1810       }
1811     }
1812
1813     // align the model properly for FGFS
1814     ssgTransform *acmodel_align = new ssgTransform;
1815     acmodel_align->addKid(acmodel_obj);
1816     sgMat4 rot_matrix;
1817     sgMat4 off_matrix;
1818     sgMat4 res_matrix;
1819     float h_rot = fgGetFloat("/sim/model/heading-offset-deg", 0.0);
1820     float p_rot = fgGetFloat("/sim/model/roll-offset-deg", 0.0);
1821     float r_rot = fgGetFloat("/sim/model/pitch-offset-deg", 0.0);
1822     float x_off = fgGetFloat("/sim/model/x-offset-m", 0.0);
1823     float y_off = fgGetFloat("/sim/model/y-offset-m", 0.0);
1824     float z_off = fgGetFloat("/sim/model/z-offset-m", 0.0);
1825     sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
1826     sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
1827     sgMultMat4(res_matrix, off_matrix, rot_matrix);
1828     acmodel_align->setTransform(res_matrix);
1829
1830     acmodel_pos->addKid( acmodel_align );
1831     acmodel_selector->addKid( acmodel_pos );
1832     //ssgFlatten( acmodel_obj );
1833     //ssgStripify( acmodel_selector );
1834     acmodel_selector->clrTraversalMaskBits( SSGTRAV_HOT );
1835     scene->addKid( acmodel_selector );
1836
1837 #ifdef FG_NETWORK_OLK
1838     // Do the network intialization
1839     if ( fgGetBool("/sim/networking/network-olk") ) {
1840         printf("Multipilot mode %s\n", fg_net_init( scene ) );
1841     }
1842 #endif
1843
1844     // build our custom render states
1845     fgBuildRenderStates();
1846
1847     // pass control off to the master GLUT event handler
1848     glutMainLoop();
1849
1850     // we never actually get here ... but to avoid compiler warnings,
1851     // etc.
1852     return 0;
1853 }
1854
1855
1856 // $$$ end - added VS Renganathan, 15 Oct 2K
1857 //         - added Venky         , 12 Nov 2K
1858
1859 // Main entry point; catch any exceptions that have made it this far.
1860 int main ( int argc, char **argv ) {
1861
1862 #if defined( _MSC_VER ) && defined( DEBUG )
1863     // Christian, we should document what this does
1864     _control87( _EM_INEXACT, _MCW_EM );
1865 #endif
1866
1867 #if defined( HAVE_BC5PLUS )
1868     _control87(MCW_EM, MCW_EM);  /* defined in float.h */
1869 #endif
1870
1871     // FIXME: add other, more specific
1872     // exceptions.
1873     try {
1874         mainLoop(argc, argv);
1875     } catch (sg_throwable &t) {
1876         SG_LOG(SG_GENERAL, SG_ALERT,
1877                "Fatal error: " << t.getFormattedMessage()
1878                << "\n (received from " << t.getOrigin() << ')');
1879         exit(1);
1880     }
1881
1882     return 0;
1883 }
1884
1885
1886 void fgLoadDCS(void) {
1887
1888     ssgEntity *ship_obj = NULL;
1889
1890     char obj_filename[25];
1891
1892     for ( int k = 0; k < 32; k++ ) {
1893         ship_pos[k]=NULL;
1894     }
1895
1896     SGPath tile_path( globals->get_fg_root());
1897     tile_path.append( "Scenery" );
1898     tile_path.append( "Objects.txt" );
1899     sg_gzifstream in( tile_path.str() );
1900     if ( ! in.is_open() ) {
1901         SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: " << tile_path.str() );
1902     } else {
1903
1904         SGPath modelpath( globals->get_fg_root() );
1905         modelpath.append( "Models" );
1906         modelpath.append( "Geometry" );
1907   
1908         SGPath texturepath( globals->get_fg_root() );
1909         texturepath.append( "Models" );
1910         texturepath.append( "Textures" );
1911  
1912         ssgModelPath( (char *)modelpath.c_str() );
1913         ssgTexturePath( (char *)texturepath.c_str() );
1914
1915         ship_sel = new ssgSelector;
1916
1917         char c;
1918         while ( ! in.eof() ) {
1919             in >> ::skipws;
1920             if ( in.get( c ) && c == '#' ) { 
1921                 in >> skipeol;
1922             } else { 
1923                 in.putback(c);
1924                 in >> obj_filename >> obj_lat[objc] >> obj_lon[objc] >> obj_alt[objc];
1925                 /* cout << endl << obj_filename << " " << obj_lat[objc] << " " << obj_lon[objc] <<  " " << obj_alt[objc] << endl;
1926                    int chj=getchar();*/
1927                 
1928                 obj_lon[objc] *=SGD_DEGREES_TO_RADIANS;
1929                 obj_lat[objc] *=SGD_DEGREES_TO_RADIANS;
1930                 
1931                 ship_pos[objc] = new ssgTransform;
1932        
1933                 // type "repeat" in objects.txt to load one more
1934                 // instance of the last object.
1935
1936                 if ( strcmp(obj_filename,"repeat") != 0) {
1937                     ship_obj = ssgLoad( obj_filename );
1938                 }
1939       
1940                 if ( ship_obj != NULL ) {
1941                                         ship_obj->setName(obj_filename);
1942                                 if (objc == 0)
1943                                                 ship_obj->clrTraversalMaskBits( SSGTRAV_HOT );
1944                                         else
1945                                                 ship_obj->setTraversalMaskBits( SSGTRAV_HOT );
1946                     ship_pos[objc]->addKid( ship_obj ); // add object to transform node
1947                     ship_sel->addKid( ship_pos[objc] ); // add transform node to selector
1948                     SG_LOG( SG_TERRAIN, SG_ALERT, "Loaded file: "
1949                             << obj_filename );
1950                 } else {
1951                     SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: "
1952                             << obj_filename );
1953                 }
1954             
1955                                 // temporary hack for deck lights - ultimately should move to PLib (when??)
1956                                 //const char *extn = file_extension ( obj_filename ) ;
1957                                 if ( objc == 1 ){
1958                                     ssgVertexArray *lights = new ssgVertexArray( 100 );
1959                                         ssgVertexArray *lightpoints = new ssgVertexArray( 100 );
1960                                         ssgVertexArray *lightnormals = new ssgVertexArray( 100 );
1961                                         ssgVertexArray *lightdir = new ssgVertexArray( 100 );
1962                                         int ltype[500], light_type;
1963                                         static int ltcount = 0;
1964                                     string token;
1965                                         sgVec3 rway_dir,rway_normal,lightpt;
1966                                         Point3D node;
1967                                         modelpath.append(obj_filename);
1968                                         sg_gzifstream in1( modelpath.str() );
1969                                         if ( ! in1.is_open() ) {
1970                                                 SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: " << modelpath.str() );
1971                                         } else {
1972                                                 while ( ! in1.eof() ) {
1973                                                         in1 >> ::skipws;
1974                                                         if ( in1.get( c ) && c == '#' ) { 
1975                                                                 in1 >> skipeol;
1976                                                         } else { 
1977                                                                 in1.putback(c);
1978                                                                 in1 >> token;
1979                                                                 //cout << token << endl;
1980                                                                 if ( token == "runway" ) {
1981                                                                         in1 >> node;
1982                                                                         sgSetVec3 (rway_dir, node[0], node[1], node[2] );                        
1983                                                                 } else if ( token == "edgelight" ) {
1984                                                                         in1 >> node;
1985                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );
1986                                                                         light_type = 1;
1987                                                                 } else if ( token == "taxi" ) {
1988                                                                         in1 >> node;
1989                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );                     
1990                                                                         light_type = 2;
1991                                                                 } else if ( token == "vasi" ) {
1992                                                                         in1 >> node;
1993                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );                     
1994                                                                         light_type = 3;
1995                                                                 } else if ( token == "threshold" ) {
1996                                                                         in1 >> node;
1997                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );                     
1998                                                                         light_type = 4;
1999                                                                 } else if ( token == "rabbit" ) {
2000                                                                         in1 >> node;
2001                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );
2002                                                                         light_type = 5;
2003                                                                 } else if ( token == "ols" ) {
2004                                                                         in1 >> node;
2005                                                                         sgSetVec3 (rway_ols, node[0], node[1], node[2] );
2006                                                                         light_type = 6;
2007                                                                 } else if ( token == "red" ) {
2008                                                                         in1 >> node;
2009                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );
2010                                                                         light_type = 7;
2011                                                                 } else if ( token == "green" ) {
2012                                                                         in1 >> node;
2013                                                                         sgSetVec3 (rway_normal, node[0], node[1], node[2] );
2014                                                                         light_type = 8;
2015                                                                 } else if ( token == "lp" ) {
2016                                                                         in1 >> node;
2017                                                                         sgSetVec3 (lightpt, node[0], node[1], node[2] );
2018                                                                         lightpoints->add( lightpt );
2019                                                                         lightnormals->add( rway_normal );
2020                                                                         lightdir->add( rway_dir );
2021                                                                         ltype[ltcount]= light_type;
2022                                                                         ltcount++;
2023                                                                 }
2024                                                                 if (in1.eof()) break;
2025                                                         } 
2026                                                 }  //while
2027         
2028                                                 if ( lightpoints->getNum() ) {
2029                                                         ssgBranch *lightpoints_branch;
2030                                                         long int dummy = -999;
2031                                                         dummy_tile = new FGTileEntry((SGBucket)dummy);
2032                                                         dummy_tile->lightmaps_sequence = new ssgSelector;
2033                                                         dummy_tile->ols_transform = new ssgTransform;
2034
2035                                                         // call function to generate the runway lights
2036                                                         lightpoints_branch = 
2037                                                         dummy_tile->gen_runway_lights( lightpoints, lightnormals,
2038                                                                                                                                 lightdir, ltype);
2039                                                         lightpoints_brightness->addKid(lightpoints_branch);
2040                                                         lightpoints_transform->addKid(lightpoints_brightness);
2041                                                     //dummy_tile->lightmaps_sequence->setTraversalMaskBits( SSGTRAV_HOT );
2042                                                         lightpoints_transform->addKid( dummy_tile->lightmaps_sequence );
2043                                                         lightpoints_transform->ref();
2044                                                         ground->addKid( lightpoints_transform );
2045                                                 } 
2046                                         } //if in1 
2047                 } //if objc
2048                                 // end hack for deck lights
2049
2050                 objc++;
2051
2052                 if (in.eof()) break;
2053             }
2054         } // while
2055
2056         SG_LOG ( SG_TERRAIN, SG_ALERT, "Finished object processing." );
2057
2058         terrain->addKid( ship_sel ); //add selector node to root node 
2059     }
2060
2061     return;
2062  }
2063
2064
2065 void fgUpdateDCS (void) {
2066
2067     // double eye_lat,eye_lon,eye_alt;
2068     // static double obj_head;
2069     double sl_radius,obj_latgc;
2070     // float nresultmat[4][4];
2071     // sgMat4 Trans,rothead,rotlon,rot180,rotlat,resultmat1,resultmat2,resultmat3;
2072     double bz[3];
2073
2074     // Instantaneous Geodetic Lat/Lon/Alt of moving object
2075     FGADA *fdm = (FGADA *)current_aircraft.fdm_state;
2076     
2077     // Deck should be the first object in objects.txt in case of fdm=ada
2078
2079     if (fgGetString("/sim/flight-model") == "ada") {
2080                 if ((fdm->get_iaux(1))==1)
2081                 {
2082                         obj_lat[1] = fdm->get_daux(1)*SGD_DEGREES_TO_RADIANS;
2083                         obj_lon[1] = fdm->get_daux(2)*SGD_DEGREES_TO_RADIANS;
2084                         obj_alt[1] = fdm->get_daux(3);
2085                         obj_pitch[1] = fdm->get_faux(1);
2086                         obj_roll[1] = fdm->get_faux(2);
2087                 }
2088     }
2089     
2090     for ( int m = 0; m < objc; m++ ) {
2091         //cout << endl <<  obj_lat[m]*SGD_RADIANS_TO_DEGREES << " " << obj_lon[m]*SGD_RADIANS_TO_DEGREES << " " << obj_alt[m] << " " << objc << endl;
2092         //int v=getchar();
2093
2094         //Geodetic to Geocentric angles for rotation
2095         sgGeodToGeoc(obj_lat[m],obj_alt[m],&sl_radius,&obj_latgc);
2096
2097         //moving object gbs-posn in cartesian coords
2098         Point3D obj_posn = Point3D( obj_lon[m],obj_lat[m],obj_alt[m]);
2099         Point3D obj_pos = sgGeodToCart( obj_posn );
2100
2101         // Translate moving object w.r.t eye
2102         Point3D Objtrans = obj_pos-scenery.center;
2103         bz[0]=Objtrans.x();
2104         bz[1]=Objtrans.y();
2105         bz[2]=Objtrans.z();
2106
2107        // rotate dynamic objects for lat,lon & alt and other motion about its axes
2108         
2109         sgMat4 sgTRANS;
2110         sgMakeTransMat4( sgTRANS, bz[0],bz[1],bz[2]);
2111
2112         sgVec3 ship_fwd,ship_rt,ship_up;
2113         sgSetVec3( ship_fwd, 1.0, 0.0, 0.0);//east,roll
2114         sgSetVec3( ship_rt, 0.0, 1.0, 0.0);//up,pitch
2115         sgSetVec3( ship_up, 0.0, 0.0, 1.0); //north,yaw
2116
2117         sgMat4 sgROT_lon, sgROT_lat, sgROT_hdg, sgROT_pitch, sgROT_roll;
2118         sgMakeRotMat4( sgROT_lon, obj_lon[m]*SGD_RADIANS_TO_DEGREES, ship_up );
2119         sgMakeRotMat4( sgROT_lat, 90-obj_latgc*SGD_RADIANS_TO_DEGREES, ship_rt );
2120         sgMakeRotMat4( sgROT_hdg, 180.0, ship_up );
2121         sgMakeRotMat4( sgROT_pitch, obj_pitch[m], ship_rt );
2122         sgMakeRotMat4( sgROT_roll, obj_roll[m], ship_fwd );
2123         
2124         sgMat4 sgTUX;
2125         sgCopyMat4( sgTUX, sgROT_hdg );
2126         sgPostMultMat4( sgTUX, sgROT_pitch );
2127         sgPostMultMat4( sgTUX, sgROT_roll );
2128         sgPostMultMat4( sgTUX, sgROT_lat );
2129         sgPostMultMat4( sgTUX, sgROT_lon );
2130         sgPostMultMat4( sgTUX, sgTRANS );
2131
2132         sgCoord shippos;
2133         sgSetCoord(&shippos, sgTUX );
2134         ship_pos[m]->setTransform( &shippos );
2135         // temporary hack for deck lights - ultimately should move to PLib (when ??)
2136         if (m == 1) {
2137                 if (lightpoints_transform) {
2138                         lightpoints_transform->setTransform( &shippos );
2139                         float sun_angle = cur_light_params.sun_angle * SGD_RADIANS_TO_DEGREES;
2140                         if ( sun_angle > 89 ) {
2141                                 lightpoints_brightness->select(0x01);
2142                         } else {
2143                                 lightpoints_brightness->select(0x00);
2144                         }
2145                 }
2146
2147                 float elev;
2148                 sgVec3 rp,to;
2149                 float *vp;
2150                 float alt;
2151                 float ref_elev;
2152                 sgXformPnt3( rp, rway_ols, sgTUX );
2153                 vp = globals->get_current_view()->get_view_pos();
2154             to[0] = rp[0]-vp[0];
2155             to[1] = rp[1]-vp[1];
2156             to[2] = rp[2]-vp[2];
2157                 float dist = sgLengthVec3( to );
2158                 alt = (current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER)-rway_ols[2];
2159
2160                 elev = asin(alt/dist)*SGD_RADIANS_TO_DEGREES;
2161
2162             ref_elev = elev - 3.75; // +ve above, -ve below
2163         
2164                 unsigned int sel;
2165                 sel = 0xFF;
2166 // DO NOT DELETE THIS CODE - This is to compare a discrete FLOLS (without LOD) with analog FLOLS
2167 //              if (ref_elev > 0.51) sel = 0x21;
2168 //              if ((ref_elev <= 0.51) & (ref_elev > 0.17)) sel = 0x22;
2169 //              if ((ref_elev <= 0.17) & (ref_elev >= -0.17)) sel = 0x24;
2170 //              if ((ref_elev < -0.17) & (ref_elev >= -0.51)) sel = 0x28;
2171 //              if (ref_elev < -0.51) sel = 0x30;
2172 // DO NOT DELETE THIS CODE - This is to compare a discrete FLOLS (without LOD) with analog FLOLS
2173                 dummy_tile->lightmaps_sequence->select(sel);
2174
2175                 sgVec3 up;
2176                 sgCopyVec3 (up, ship_up);
2177                 if (dist > 750) 
2178                         sgScaleVec3 (up, 4.0*ref_elev*dist/750.0);
2179                 else
2180                         sgScaleVec3 (up, 4.0*ref_elev);
2181                 dummy_tile->ols_transform->setTransform(up);
2182                 //cout << "ref_elev  " << ref_elev << endl;
2183         }
2184     // end hack for deck lights
2185
2186     }
2187     if ( ship_sel != NULL ) {
2188         ship_sel->select(0xFFFFFFFE); // first object is ownship, added to acmodel
2189     }
2190 }
2191
2192 // $$$ end - added VS Renganathan, 15 Oct 2K
2193 //           added Venky         , 12 Nov 2K