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