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