]> git.mxchange.org Git - flightgear.git/blob - src/Main/GLUTmain.cxx
source tree reorganization prior to flightgear 0.7
[flightgear.git] / src / Main / GLUTmain.cxx
1 // GLUTmain.cxx -- top level sim routines
2 //
3 // Written by Curtis Olson for OpenGL, started May 1997.
4 //
5 // Copyright (C) 1997  Curtis L. Olson  - curt@me.umn.edu
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 #define MICHAEL_JOHNSON_EXPERIMENTAL_ENGINE_AUDIO
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #ifdef FG_MATH_EXCEPTION_CLASH
30 #  include <math.h>
31 #endif
32
33 #ifdef HAVE_WINDOWS_H
34 #  include <windows.h>                     
35 #  include <float.h>                    
36 #endif
37
38 #include <GL/glut.h>
39 #include <XGL/xgl.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <string>
43
44 #ifdef HAVE_STDLIB_H
45 #   include <stdlib.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 #  include <sys/stat.h> /* for stat() */
50 #endif
51
52 #ifdef HAVE_UNISTD_H
53 #  include <unistd.h>    /* for stat() */
54 #endif
55
56 #include <Include/fg_constants.h>  // for VERSION
57 #include <Include/general.hxx>
58
59 #include <Debug/logstream.hxx>
60 #include <Aircraft/aircraft.hxx>
61 #include <Astro/sky.hxx>
62 #include <Astro/stars.hxx>
63 #include <Astro/solarsystem.hxx>
64
65 #ifdef ENABLE_AUDIO_SUPPORT
66 #  include <plib/sl.h>
67 #  include <plib/sm.h>
68 #endif
69
70 #include <Autopilot/autopilot.hxx>
71 #include <Cockpit/cockpit.hxx>
72 #include <GUI/gui.h>
73 #include <Joystick/joystick.hxx>
74 #include <Math/fg_geodesy.hxx>
75 #include <Math/mat3.h>
76 #include <Math/polar3d.hxx>
77 #include <Math/fg_random.h>
78 #include <Misc/fgpath.hxx>
79 #include <plib/pu.h>
80 #include <Scenery/scenery.hxx>
81 #include <Scenery/tilemgr.hxx>
82 #include <Time/event.hxx>
83 #include <Time/fg_time.hxx>
84 #include <Time/fg_timer.hxx>
85 #include <Time/sunpos.hxx>
86 #include <Weather/weather.hxx>
87
88 #include "GLUTkey.hxx"
89 #include "fg_init.hxx"
90 #include "options.hxx"
91 #include "splash.hxx"
92 #include "views.hxx"
93 #include "fg_serial.hxx"
94
95
96 // -dw- use custom sioux settings so I can see output window
97 #ifdef MACOS
98 #  ifndef FG_NDEBUG
99 #    include <sioux.h> // settings for output window
100 #  endif
101 #  include <console.h>
102 #endif
103
104
105 // This is a record containing a bit of global housekeeping information
106 FGGeneral general;
107
108 // Specify our current idle function state.  This is used to run all
109 // our initializations out of the glutIdleLoop() so that we can get a
110 // splash screen up and running right away.
111 static int idle_state = 0;
112
113 // Another hack
114 int use_signals = 0;
115
116 // Global structures for the Audio library
117 #ifdef ENABLE_AUDIO_SUPPORT
118 slEnvelope pitch_envelope ( 1, SL_SAMPLE_ONE_SHOT ) ;
119 slEnvelope volume_envelope ( 1, SL_SAMPLE_ONE_SHOT ) ;
120 slScheduler *audio_sched;
121 smMixer *audio_mixer;
122 slSample *s1;
123 slSample *s2;
124 #endif
125
126
127 // The following defines flight gear options. Because glutlib will also
128 // want to parse its own options, those options must not be included here
129 // or they will get parsed by the main program option parser. Hence case
130 // is significant for any option added that might be in conflict with
131 // glutlib's parser.
132 //
133 // glutlib parses for:
134 //    -display
135 //    -direct   (invalid in Win32)
136 //    -geometry
137 //    -gldebug
138 //    -iconized
139 //    -indirect (invalid in Win32)
140 //    -synce
141 //
142 // Note that glutlib depends upon strings while this program's
143 // option parser wants only initial characters followed by numbers
144 // or pathnames.
145 //
146
147
148 // fgInitVisuals() -- Initialize various GL/view parameters
149 static void fgInitVisuals( void ) {
150     fgLIGHT *l;
151
152     l = &cur_light_params;
153
154 #ifndef GLUT_WRONG_VERSION
155     // Go full screen if requested ...
156     if ( current_options.get_fullscreen() ) {
157         glutFullScreen();
158     }
159 #endif
160
161     // If enabled, normal vectors specified with glNormal are scaled
162     // to unit length after transformation.  See glNormal.
163     // xglEnable( GL_NORMALIZE );
164
165     xglEnable( GL_LIGHTING );
166     xglEnable( GL_LIGHT0 );
167     xglLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
168
169     // xglFogi (GL_FOG_MODE, GL_LINEAR);
170     xglFogi (GL_FOG_MODE, GL_EXP2);
171     // Fog density is now set when the weather system is initialized
172     // xglFogf (GL_FOG_DENSITY, w->fog_density);
173     if ( (current_options.get_fog() == 1) || 
174          (current_options.get_shading() == 0) ) {
175         // if fastest fog requested, or if flat shading force fastest
176         xglHint ( GL_FOG_HINT, GL_FASTEST );
177     } else if ( current_options.get_fog() == 2 ) {
178         xglHint ( GL_FOG_HINT, GL_NICEST );
179     }
180     if ( current_options.get_wireframe() ) {
181         // draw wire frame
182         xglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
183     }
184
185     // This is the default anyways, but it can't hurt
186     xglFrontFace ( GL_CCW );
187
188     // Just testing ...
189     // xglEnable(GL_POINT_SMOOTH);
190     // xglEnable(GL_LINE_SMOOTH);
191     // xglEnable(GL_POLYGON_SMOOTH);      
192 }
193
194
195 #if 0
196 // Draw a basic instrument panel
197 static void fgUpdateInstrViewParams( void ) {
198
199     exit(0);
200
201     fgVIEW *v = &current_view;
202
203     xglViewport(0, 0 , (GLint)(v->winWidth), (GLint)(v->winHeight) / 2);
204   
205     xglMatrixMode(GL_PROJECTION);
206     xglPushMatrix();
207   
208     xglLoadIdentity();
209     gluOrtho2D(0, 640, 0, 480);
210     xglMatrixMode(GL_MODELVIEW);
211     xglPushMatrix();
212     xglLoadIdentity();
213
214     xglColor3f(1.0, 1.0, 1.0);
215     xglIndexi(7);
216   
217     xglDisable(GL_DEPTH_TEST);
218     xglDisable(GL_LIGHTING);
219   
220     xglLineWidth(1);
221     xglColor3f (0.5, 0.5, 0.5);
222
223     xglBegin(GL_QUADS);
224     xglVertex2f(0.0, 0.00);
225     xglVertex2f(0.0, 480.0);
226     xglVertex2f(640.0,480.0);
227     xglVertex2f(640.0, 0.0);
228     xglEnd();
229
230     xglRectf(0.0,0.0, 640, 480);
231     xglEnable(GL_DEPTH_TEST);
232     xglEnable(GL_LIGHTING);
233     xglMatrixMode(GL_PROJECTION);
234     xglPopMatrix();
235     xglMatrixMode(GL_MODELVIEW);
236     xglPopMatrix();
237 }
238 #endif
239
240
241 // Update all Visuals (redraws anything graphics related)
242 static void fgRenderFrame( void ) {
243     fgLIGHT *l = &cur_light_params;
244     FGTime *t = FGTime::cur_time_params;
245     FGView *v = &current_view;
246
247     double angle;
248     // GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
249     GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
250     GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
251     // GLfloat mat_shininess[] = { 10.0 };
252     GLbitfield clear_mask;
253
254     if ( idle_state != 1000 ) {
255         // still initializing, draw the splash screen
256         if ( current_options.get_splash_screen() == 1 ) {
257             fgSplashUpdate(0.0);
258         }
259     } else {
260         // idle_state is now 1000 meaning we've finished all our
261         // initializations and are running the main loop, so this will
262         // now work without seg faulting the system.
263
264         // printf("Ground = %.2f  Altitude = %.2f\n", scenery.cur_elev, 
265         //        FG_Altitude * FEET_TO_METER);
266     
267         // this is just a temporary hack, to make me understand Pui
268         // timerText -> setLabel (ctime (&t->cur_time));
269         // end of hack
270
271         // update view volume parameters
272         v->UpdateViewParams();
273
274         // set the sun position
275         xglLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
276
277         clear_mask = GL_DEPTH_BUFFER_BIT;
278         if ( current_options.get_wireframe() ) {
279             clear_mask |= GL_COLOR_BUFFER_BIT;
280         }
281         if ( current_options.get_panel_status() ) {
282             // we can't clear the screen when the panel is active
283         } else if ( current_options.get_skyblend() ) {
284             if ( current_options.get_textures() ) {
285                 // glClearColor(black[0], black[1], black[2], black[3]);
286                 glClearColor(l->adj_fog_color[0], l->adj_fog_color[1], 
287                              l->adj_fog_color[2], l->adj_fog_color[3]);
288                 clear_mask |= GL_COLOR_BUFFER_BIT;
289             }
290         } else {
291             glClearColor(l->sky_color[0], l->sky_color[1], 
292                          l->sky_color[2], l->sky_color[3]);
293             clear_mask |= GL_COLOR_BUFFER_BIT;
294         }
295         xglClear( clear_mask );
296
297         // Tell GL we are switching to model view parameters
298         xglMatrixMode(GL_MODELVIEW);
299         // xglLoadIdentity();
300
301         // draw sky
302         xglDisable( GL_DEPTH_TEST );
303         xglDisable( GL_LIGHTING );
304         xglDisable( GL_CULL_FACE );
305         xglDisable( GL_FOG );
306         xglShadeModel( GL_SMOOTH );
307         if ( current_options.get_skyblend() ) {
308             fgSkyRender();
309         }
310
311         // setup transformation for drawing astronomical objects
312         xglPushMatrix();
313         // Translate to view position
314         Point3D view_pos = v->get_view_pos();
315         xglTranslatef( view_pos.x(), view_pos.y(), view_pos.z() );
316         // Rotate based on gst (sidereal time)
317         // note: constant should be 15.041085, Curt thought it was 15
318         angle = t->getGst() * 15.041085;
319         // printf("Rotating astro objects by %.2f degrees\n",angle);
320         xglRotatef( angle, 0.0, 0.0, -1.0 );
321
322         // draw stars and planets
323         fgStarsRender();
324         xglEnable( GL_CULL_FACE ); // for moon
325         //xglEnable(GL_DEPTH_TEST);
326         SolarSystem::theSolarSystem->draw();
327
328         xglPopMatrix();
329
330         // draw scenery
331         if ( current_options.get_shading() ) {
332             xglShadeModel( GL_SMOOTH ); 
333         } else {
334             xglShadeModel( GL_FLAT ); 
335         }
336         xglEnable( GL_DEPTH_TEST );
337         if ( current_options.get_fog() > 0 ) {
338             xglEnable( GL_FOG );
339             xglFogfv (GL_FOG_COLOR, l->adj_fog_color);
340         }
341         // set lighting parameters
342         xglLightfv(GL_LIGHT0, GL_AMBIENT, l->scene_ambient );
343         xglLightfv(GL_LIGHT0, GL_DIFFUSE, l->scene_diffuse );
344         // xglLightfv(GL_LIGHT0, GL_SPECULAR, white );
345         
346         if ( current_options.get_textures() ) {
347             // texture parameters
348             xglEnable( GL_TEXTURE_2D );
349             xglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
350             xglHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
351             // set base color (I don't think this is doing anything here)
352             xglMaterialfv (GL_FRONT, GL_AMBIENT, white);
353             xglMaterialfv (GL_FRONT, GL_DIFFUSE, white);
354             // xglMaterialfv (GL_FRONT, GL_SPECULAR, white);
355             // xglMaterialfv (GL_FRONT, GL_SHININESS, mat_shininess);
356         } else {
357             xglDisable( GL_TEXTURE_2D );
358             xglMaterialfv (GL_FRONT, GL_AMBIENT, terrain_color);
359             xglMaterialfv (GL_FRONT, GL_DIFFUSE, terrain_color);
360             // xglMaterialfv (GL_FRONT, GL_AMBIENT, white);
361             // xglMaterialfv (GL_FRONT, GL_DIFFUSE, white);
362         }
363
364         global_tile_mgr.render();
365
366         xglDisable( GL_TEXTURE_2D );
367         xglDisable( GL_FOG );
368
369         // display HUD && Panel
370         xglDisable( GL_CULL_FACE );
371         fgCockpitUpdate();
372
373         // We can do translucent menus, so why not. :-)
374         xglEnable    ( GL_BLEND ) ;
375         xglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
376         puDisplay();
377         xglDisable   ( GL_BLEND ) ;
378         xglEnable( GL_FOG );
379     }
380
381     xglutSwapBuffers();
382 }
383
384
385 // Update internal time dependent calculations (i.e. flight model)
386 void fgUpdateTimeDepCalcs(int multi_loop, int remainder) {
387     FGInterface *f = current_aircraft.fdm_state;
388     fgLIGHT *l = &cur_light_params;
389     FGTime *t = FGTime::cur_time_params;
390     FGView *v = &current_view;
391     int i;
392
393     // update the flight model
394     if ( multi_loop < 0 ) {
395         multi_loop = DEFAULT_MULTILOOP;
396     }
397
398     if ( !t->getPause() ) {
399         // run Autopilot system
400         fgAPRun();
401
402         // printf("updating flight model x %d\n", multi_loop);
403         fgFDMUpdate( current_options.get_flight_model(), 
404                      cur_fdm_state, multi_loop, remainder );
405     } else {
406         fgFDMUpdate( current_options.get_flight_model(), 
407                      cur_fdm_state, 0, remainder );
408     }
409
410     // update the view angle
411     for ( i = 0; i < multi_loop; i++ ) {
412         if ( fabs(v->get_goal_view_offset() - v->get_view_offset()) < 0.05 ) {
413             v->set_view_offset( v->get_goal_view_offset() );
414             break;
415         } else {
416             // move v->view_offset towards v->goal_view_offset
417             if ( v->get_goal_view_offset() > v->get_view_offset() ) {
418                 if ( v->get_goal_view_offset() - v->get_view_offset() < FG_PI ){
419                     v->inc_view_offset( 0.01 );
420                 } else {
421                     v->inc_view_offset( -0.01 );
422                 }
423             } else {
424                 if ( v->get_view_offset() - v->get_goal_view_offset() < FG_PI ){
425                     v->inc_view_offset( -0.01 );
426                 } else {
427                     v->inc_view_offset( 0.01 );
428                 }
429             }
430             if ( v->get_view_offset() > FG_2PI ) {
431                 v->inc_view_offset( -FG_2PI );
432             } else if ( v->get_view_offset() < 0 ) {
433                 v->inc_view_offset( FG_2PI );
434             }
435         }
436     }
437
438     double tmp = -(l->sun_rotation + FG_PI) 
439         - (f->get_Psi() - v->get_view_offset() );
440     while ( tmp < 0.0 ) {
441         tmp += FG_2PI;
442     }
443     while ( tmp > FG_2PI ) {
444         tmp -= FG_2PI;
445     }
446     /* printf("Psi = %.2f, viewoffset = %.2f sunrot = %.2f rottosun = %.2f\n",
447            FG_Psi * RAD_TO_DEG, v->view_offset * RAD_TO_DEG, 
448            -(l->sun_rotation+FG_PI) * RAD_TO_DEG, tmp * RAD_TO_DEG); */
449     l->UpdateAdjFog();
450 }
451
452
453 void fgInitTimeDepCalcs( void ) {
454     // initialize timer
455
456     // #ifdef HAVE_SETITIMER
457     //   fgTimerInit( 1.0 / DEFAULT_TIMER_HZ, fgUpdateTimeDepCalcs );
458     // #endif HAVE_SETITIMER
459 }
460
461 static const double alt_adjust_ft = 3.758099;
462 static const double alt_adjust_m = alt_adjust_ft * FEET_TO_METER;
463
464 // What should we do when we have nothing else to do?  Let's get ready
465 // for the next move and update the display?
466 static void fgMainLoop( void ) {
467     FGInterface *f;
468     FGTime *t;
469     static long remainder = 0;
470     long elapsed, multi_loop;
471 #ifdef FANCY_FRAME_COUNTER
472     int i;
473     double accum;
474 #else
475     static time_t last_time = 0;
476     static int frames = 0;
477 #endif // FANCY_FRAME_COUNTER
478
479     f = current_aircraft.fdm_state;
480     t = FGTime::cur_time_params;
481
482     FG_LOG( FG_ALL, FG_DEBUG, "Running Main Loop");
483     FG_LOG( FG_ALL, FG_DEBUG, "======= ==== ====");
484
485 #if defined( ENABLE_PLIB_JOYSTICK )
486     // Read joystick and update control settings
487     fgJoystickRead();
488 #elif defined( ENABLE_GLUT_JOYSTICK )
489     // Glut joystick support works by feeding a joystick handler
490     // function to glut.  This is taken care of once in the joystick
491     // init routine and we don't have to worry about it again.
492 #endif
493
494     current_weather.Update();
495
496     // Fix elevation.  I'm just sticking this here for now, it should
497     // probably move eventually
498
499     /* printf("Before - ground = %.2f  runway = %.2f  alt = %.2f\n",
500            scenery.cur_elev,
501            f->get_Runway_altitude() * FEET_TO_METER,
502            f->get_Altitude() * FEET_TO_METER); */
503
504     if ( scenery.cur_elev > -9990 ) {
505         if ( f->get_Altitude() * FEET_TO_METER < 
506              (scenery.cur_elev + alt_adjust_m - 3.0) ) {
507             // now set aircraft altitude above ground
508             printf("Current Altitude = %.2f < %.2f forcing to %.2f\n", 
509                    f->get_Altitude() * FEET_TO_METER,
510                    scenery.cur_elev + alt_adjust_m - 3.0,
511                    scenery.cur_elev + alt_adjust_m );
512             fgFDMForceAltitude( current_options.get_flight_model(), 
513                                 scenery.cur_elev + alt_adjust_m );
514
515             FG_LOG( FG_ALL, FG_DEBUG, 
516                     "<*> resetting altitude to " 
517                     << f->get_Altitude() * FEET_TO_METER << " meters" );
518         }
519         fgFDMSetGroundElevation( current_options.get_flight_model(),
520                                  scenery.cur_elev );  // meters
521     }
522
523     /* printf("Adjustment - ground = %.2f  runway = %.2f  alt = %.2f\n",
524            scenery.cur_elev,
525            f->get_Runway_altitude() * FEET_TO_METER,
526            f->get_Altitude() * FEET_TO_METER); */
527
528     // update "time"
529     t->update(f);
530
531     // Get elapsed time (in usec) for this past frame
532     elapsed = fgGetTimeInterval();
533     FG_LOG( FG_ALL, FG_DEBUG, 
534             "Elapsed time interval is = " << elapsed 
535             << ", previous remainder is = " << remainder );
536
537     // Calculate frame rate average
538 #ifdef FANCY_FRAME_COUNTER
539     /* old fps calculation */
540     if ( elapsed > 0 ) {
541         double tmp;
542         accum = 0.0;
543         for ( i = FG_FRAME_RATE_HISTORY - 2; i >= 0; i-- ) {
544             tmp = general.get_frame(i);
545             accum += tmp;
546             // printf("frame[%d] = %.2f\n", i, g->frames[i]);
547             general.set_frame(i+1,tmp);
548         }
549         tmp = 1000000.0 / (float)elapsed;
550         general.set_frame(0,tmp);
551         // printf("frame[0] = %.2f\n", general.frames[0]);
552         accum += tmp;
553         general.set_frame_rate(accum / (float)FG_FRAME_RATE_HISTORY);
554         // printf("ave = %.2f\n", general.frame_rate);
555     }
556 #else
557     if ( (t->get_cur_time() != last_time) && (last_time > 0) ) {
558         general.set_frame_rate( frames );
559         FG_LOG( FG_ALL, FG_DEBUG, 
560                 "--> Frame rate is = " << general.get_frame_rate() );
561         frames = 0;
562     }
563     last_time = t->get_cur_time();
564     ++frames;
565 #endif
566
567     // Run flight model
568     if ( ! use_signals ) {
569         // Calculate model iterations needed for next frame
570         elapsed += remainder;
571
572         multi_loop = (int)(((double)elapsed * 0.000001) * DEFAULT_MODEL_HZ);
573         remainder = elapsed - ((multi_loop*1000000) / DEFAULT_MODEL_HZ);
574         FG_LOG( FG_ALL, FG_DEBUG, 
575                 "Model iterations needed = " << multi_loop
576                 << ", new remainder = " << remainder );
577         
578         // flight model
579         if ( multi_loop > 0 ) {
580             fgUpdateTimeDepCalcs(multi_loop, remainder);
581         } else {
582             FG_LOG( FG_ALL, FG_INFO, "Elapsed time is zero ... we're zinging" );
583         }
584     }
585
586 #if ! defined( MACOS )
587     // Do any serial port work that might need to be done
588     fgSerialProcess();
589 #endif
590
591     // see if we need to load any new scenery tiles
592     global_tile_mgr.update();
593
594     // Process/manage pending events
595     global_events.Process();
596
597     // Run audio scheduler
598 #ifdef ENABLE_AUDIO_SUPPORT
599     if ( current_options.get_sound() && !audio_sched->not_working() ) {
600
601 #   ifdef MICHAEL_JOHNSON_EXPERIMENTAL_ENGINE_AUDIO
602
603         // note: all these factors are relative to the sample.  our
604         // sample format should really contain a conversion factor so
605         // that we can get prop speed right for arbitrary samples.
606         // Note that for normal-size props, there is a point at which
607         // the prop tips approach the speed of sound; that is a pretty
608         // strong limit to how fast the prop can go.
609
610         // multiplication factor is prime pitch control; add some log
611         // component for verisimilitude
612
613         double pitch = log((controls.get_throttle(0) * 14.0) + 1.0);
614         //fprintf(stderr, "pitch1: %f ", pitch);
615         if (controls.get_throttle(0) > 0.0 || f->v_rel_wind > 40.0) {
616             //fprintf(stderr, "rel_wind: %f ", f->v_rel_wind);
617             // only add relative wind and AoA if prop is moving
618             // or we're really flying at idle throttle
619             if (pitch < 5.4) {  // this needs tuning
620                 // prop tips not breaking sound barrier
621                 pitch += log(f->v_rel_wind + 0.8)/2;
622             } else {
623                 // prop tips breaking sound barrier
624                 pitch += log(f->v_rel_wind + 0.8)/10;
625             }
626             //fprintf(stderr, "pitch2: %f ", pitch);
627             //fprintf(stderr, "AoA: %f ", FG_Gamma_vert_rad);
628
629             // Angle of Attack next... -x^3(e^x) is my best guess Just
630             // need to calculate some reasonable scaling factor and
631             // then clamp it on the positive aoa (neg adj) side
632             double aoa = f->get_Gamma_vert_rad() * 2.2;
633             double tmp = 3.0;
634             double aoa_adj = pow(-aoa, tmp) * pow(M_E, aoa);
635             if (aoa_adj < -0.8) aoa_adj = -0.8;
636             pitch += aoa_adj;
637             //fprintf(stderr, "pitch3: %f ", pitch);
638
639             // don't run at absurdly slow rates -- not realistic
640             // and sounds bad to boot.  :-)
641             if (pitch < 0.8) pitch = 0.8;
642         }
643         //fprintf(stderr, "pitch4: %f\n", pitch);
644
645         double volume = controls.get_throttle(0) * 1.15 + 0.3 +
646             log(f->v_rel_wind + 1.0)/14.0;
647         // fprintf(stderr, "volume: %f\n", volume);
648
649         pitch_envelope.setStep  ( 0, 0.01, pitch );
650         volume_envelope.setStep ( 0, 0.01, volume );
651
652 #   else
653
654        double param = controls.get_throttle( 0 ) * 2.0 + 1.0;
655        pitch_envelope.setStep  ( 0, 0.01, param );
656        volume_envelope.setStep ( 0, 0.01, param );
657
658 #   endif // experimental throttle patch
659
660         audio_sched -> update();
661     }
662 #endif
663
664     // redraw display
665     fgRenderFrame();
666
667     FG_LOG( FG_ALL, FG_DEBUG, "" );
668 }
669
670
671 // This is the top level master main function that is registered as
672 // our idle funciton
673 //
674
675 // The first few passes take care of initialization things (a couple
676 // per pass) and once everything has been initialized fgMainLoop from
677 // then on.
678
679 static void fgIdleFunction ( void ) {
680     // printf("idle state == %d\n", idle_state);
681
682     if ( idle_state == 0 ) {
683         // Initialize the splash screen right away
684         if ( current_options.get_splash_screen() ) {
685             fgSplashInit();
686         }
687         
688         idle_state++;
689     } else if ( idle_state == 1 ) {
690         // Start the intro music
691 #if !defined(WIN32)
692         if ( current_options.get_intro_music() ) {
693             string lockfile = "/tmp/mpg123.running";
694             FGPath mp3file( current_options.get_fg_root() );
695             mp3file.append( "Sounds/intro.mp3" );
696
697             string command = "(touch " + lockfile + "; mpg123 "
698                 + mp3file.str() + "> /dev/null 2>&1; /bin/rm "
699                 + lockfile + ") &";
700             FG_LOG( FG_GENERAL, FG_INFO, 
701                     "Starting intro music: " << mp3file.str() );
702             system ( command.c_str() );
703         }
704 #endif
705
706         idle_state++;
707     } else if ( idle_state == 2 ) {
708         // These are a few miscellaneous things that aren't really
709         // "subsystems" but still need to be initialized.
710
711 #ifdef USE_GLIDE
712         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
713             grTexLodBiasValue ( GR_TMU0, 1.0 ) ;
714         }
715 #endif
716
717         idle_state++;
718     } else if ( idle_state == 3 ) {
719         // This is the top level init routine which calls all the
720         // other subsystem initialization routines.  If you are adding
721         // a subsystem to flight gear, its initialization call should
722         // located in this routine.
723         if( !fgInitSubsystems()) {
724             FG_LOG( FG_GENERAL, FG_ALERT,
725                     "Subsystem initializations failed ..." );
726             exit(-1);
727         }
728
729         idle_state++;
730     } else if ( idle_state == 4 ) {
731         // setup OpenGL view parameters
732         fgInitVisuals();
733
734         if ( use_signals ) {
735             // init timer routines, signals, etc.  Arrange for an alarm
736             // signal to be generated, etc.
737             fgInitTimeDepCalcs();
738         }
739
740         idle_state++;
741     } else if ( idle_state == 5 ) {
742
743         idle_state++;
744     } else if ( idle_state == 6 ) {
745         // Initialize audio support
746 #ifdef ENABLE_AUDIO_SUPPORT
747
748 #if !defined(WIN32)
749         if ( current_options.get_intro_music() ) {
750             // Let's wait for mpg123 to finish
751             string lockfile = "/tmp/mpg123.running";
752             struct stat stat_buf;
753
754             FG_LOG( FG_GENERAL, FG_INFO, 
755                     "Waiting for mpg123 player to finish ..." );
756             while ( stat(lockfile.c_str(), &stat_buf) == 0 ) {
757                 // file exist, wait ...
758                 sleep(1);
759                 FG_LOG( FG_GENERAL, FG_INFO, ".");
760             }
761             FG_LOG( FG_GENERAL, FG_INFO, "");
762         }
763 #endif // WIN32
764
765         audio_sched = new slScheduler ( 8000 );
766         audio_mixer = new smMixer;
767         audio_mixer -> setMasterVolume ( 80 ) ;  /* 80% of max volume. */
768         audio_sched -> setSafetyMargin ( 1.0 ) ;
769
770         FGPath slfile( current_options.get_fg_root() );
771         slfile.append( "Sounds/wasp.wav" );
772
773         s1 = new slSample ( (char *)slfile.c_str() );
774         FG_LOG( FG_GENERAL, FG_INFO,
775                 "Rate = " << s1 -> getRate()
776                 << "  Bps = " << s1 -> getBps()
777                 << "  Stereo = " << s1 -> getStereo() );
778         audio_sched -> loopSample ( s1 );
779
780         if ( audio_sched->not_working() ) {
781             // skip
782         } else {
783             pitch_envelope.setStep  ( 0, 0.01, 0.6 );
784             volume_envelope.setStep ( 0, 0.01, 0.6 );
785
786             audio_sched -> addSampleEnvelope( s1, 0, 0, &
787                                               pitch_envelope,
788                                               SL_PITCH_ENVELOPE );
789             audio_sched -> addSampleEnvelope( s1, 0, 1, 
790                                               &volume_envelope,
791                                               SL_VOLUME_ENVELOPE );
792         }
793
794         // strcpy(slfile, path);
795         // strcat(slfile, "thunder.wav");
796         // s2 -> loadFile ( slfile );
797         // s2 -> adjustVolume(0.5);
798         // audio_sched -> playSample ( s2 );
799 #endif
800
801         // sleep(1);
802         idle_state = 1000;
803     } 
804
805     if ( idle_state == 1000 ) {
806         // We've finished all our initialization steps, from now on we
807         // run the main loop.
808
809         fgMainLoop();
810     } else {
811         if ( current_options.get_splash_screen() == 1 ) {
812             fgSplashUpdate(0.0);
813         }
814     }
815 }
816
817 // options.cxx needs to see this for toggle_panel()
818 // Handle new window size or exposure
819 void fgReshape( int width, int height ) {
820     // Do this so we can call fgReshape(0,0) ourselves without having
821     // to know what the values of width & height are.
822     if ( (height > 0) && (width > 0) ) {
823         if ( ! current_options.get_panel_status() ) {
824             current_view.set_win_ratio( (GLfloat) width / (GLfloat) height );
825         } else {
826             current_view.set_win_ratio( (GLfloat) width / 
827                                         ((GLfloat) (height)*0.4232) );
828         }
829     }
830
831     current_view.set_winWidth( width );
832     current_view.set_winHeight( height );
833     current_view.force_update_fov_math();
834
835     // Inform gl of our view window size (now handled elsewhere)
836     // xglViewport(0, 0, (GLint)width, (GLint)height);
837     if ( idle_state == 1000 ) {
838         // yes we've finished all our initializations and are running
839         // the main loop, so this will now work without seg faulting
840         // the system.
841         current_view.UpdateViewParams();
842         if ( current_options.get_panel_status() ) {
843             FGPanel::OurPanel->ReInit(0, 0, 1024, 768);
844         }
845     }
846 }
847
848
849 // Initialize GLUT and define a main window
850 int fgGlutInit( int *argc, char **argv ) {
851
852 #if !defined( MACOS )
853     // GLUT will extract all glut specific options so later on we only
854     // need wory about our own.
855     xglutInit(argc, argv);
856 #endif
857
858     // Define Display Parameters
859     xglutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
860
861     FG_LOG( FG_GENERAL, FG_INFO, "Opening a window: " <<
862             current_options.get_xsize() << "x" << current_options.get_ysize() );
863
864     // Define initial window size
865     xglutInitWindowSize( current_options.get_xsize(),
866                          current_options.get_ysize() );
867
868     // Initialize windows
869     if ( current_options.get_game_mode() == 0 ) {
870         // Open the regular window
871         xglutCreateWindow("Flight Gear");
872 #ifndef GLUT_WRONG_VERSION
873     } else {
874         // Open the cool new 'game mode' window
875         char game_mode_str[256];
876         sprintf( game_mode_str, "width=%d height=%d bpp=32",
877                  current_options.get_xsize(),
878                  current_options.get_ysize() );
879
880         FG_LOG( FG_GENERAL, FG_INFO, 
881                 "game mode params = " << game_mode_str );
882         glutGameModeString( game_mode_str );
883         glutEnterGameMode();
884 #endif
885     }
886
887     // This seems to be the absolute earliest in the init sequence
888     // that these calls will return valid info.  Too bad it's after
889     // we've already created and sized out window. :-(
890     general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
891     general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
892     general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
893
894     FG_LOG ( FG_GENERAL, FG_INFO, general.get_glRenderer() );
895
896 #if 0
897     // try to determine if we should adjust the initial default
898     // display resolution.  The options class defaults (is
899     // initialized) to 640x480.
900     string renderer = general.glRenderer;
901
902     // currently we only know how to deal with Mesa/Glide/Voodoo cards
903     if ( renderer.find( "Glide" ) != string::npos ) {
904         FG_LOG( FG_GENERAL, FG_INFO, "Detected a Glide driver" );
905         if ( renderer.find( "FB/8" ) != string::npos ) {
906             // probably a voodoo-2
907             if ( renderer.find( "TMU/SLI" ) != string::npos ) {
908                 // probably two SLI'd Voodoo-2's
909                 current_options.set_xsize( 1024 );
910                 current_options.set_ysize( 768 );
911                 FG_LOG( FG_GENERAL, FG_INFO,
912                         "It looks like you have two sli'd voodoo-2's." << endl
913                         << "upgrading your win resolution to 1024 x 768" );
914                 glutReshapeWindow(1024, 768);
915             } else {
916                 // probably a single non-SLI'd Voodoo-2
917                 current_options.set_xsize( 800 );
918                 current_options.set_ysize( 600 );
919                 FG_LOG( FG_GENERAL, FG_INFO,
920                         "It looks like you have a voodoo-2." << endl
921                         << "upgrading your win resolution to 800 x 600" );
922                 glutReshapeWindow(800, 600);
923             }
924         } else if ( renderer.find( "FB/2" ) != string::npos ) {
925             // probably a voodoo-1, stick with the default
926         }
927     } else {
928         // we have no special knowledge of this card, stick with the default
929     }
930 #endif
931
932     return(1);
933 }
934
935
936 // Initialize GLUT event handlers
937 int fgGlutInitEvents( void ) {
938     // call fgReshape() on window resizes
939     xglutReshapeFunc( fgReshape );
940
941     // call GLUTkey() on keyboard event
942     xglutKeyboardFunc( GLUTkey );
943     glutSpecialFunc( GLUTspecialkey );
944
945     // call guiMouseFunc() whenever our little rodent is used
946     glutMouseFunc ( guiMouseFunc );
947     glutMotionFunc (guiMotionFunc );
948     glutPassiveMotionFunc (guiMotionFunc );
949
950     // call fgMainLoop() whenever there is
951     // nothing else to do
952     xglutIdleFunc( fgIdleFunction );
953
954     // draw the scene
955     xglutDisplayFunc( fgRenderFrame );
956
957     return(1);
958 }
959
960
961 // Main ...
962 int main( int argc, char **argv ) {
963
964 #if defined( MACOS )
965     argc = ccommand( &argv );
966 #endif
967
968     FGInterface *f;
969
970     f = current_aircraft.fdm_state;
971
972 #ifdef HAVE_BC5PLUS
973     _control87(MCW_EM, MCW_EM);  /* defined in float.h */
974 #endif
975
976     // set default log levels
977     fglog().setLogLevels( FG_ALL, FG_INFO );
978
979     FG_LOG( FG_GENERAL, FG_INFO, "Flight Gear:  Version " << VERSION << endl );
980
981     string root;
982
983     FG_LOG( FG_GENERAL, FG_INFO, "General Initialization" );
984     FG_LOG( FG_GENERAL, FG_INFO, "======= ==============" );
985
986     // seed the random number generater
987     fg_srandom();
988
989     // Attempt to locate and parse a config file
990     // First check fg_root
991     FGPath config( current_options.get_fg_root() );
992     config.append( "system.fgfsrc" );
993     current_options.parse_config_file( config.str() );
994
995     // Next check home directory
996     char* envp = ::getenv( "HOME" );
997     if ( envp != NULL ) {
998         config.set( envp );
999         config.append( ".fgfsrc" );
1000         current_options.parse_config_file( config.str() );
1001     }
1002
1003     // Parse remaining command line options
1004     // These will override anything specified in a config file
1005     if ( current_options.parse_command_line(argc, argv) !=
1006          fgOPTIONS::FG_OPTIONS_OK )
1007     {
1008         // Something must have gone horribly wrong with the command
1009         // line parsing or maybe the user just requested help ... :-)
1010         current_options.usage();
1011         FG_LOG( FG_GENERAL, FG_ALERT, "\nExiting ...");
1012         exit(-1);
1013     }
1014     
1015     // Initialize the Window/Graphics environment.
1016     if( !fgGlutInit(&argc, argv) ) {
1017         FG_LOG( FG_GENERAL, FG_ALERT, "GLUT initialization failed ..." );
1018         exit(-1);
1019     }
1020
1021     // Initialize the various GLUT Event Handlers.
1022     if( !fgGlutInitEvents() ) {
1023         FG_LOG( FG_GENERAL, FG_ALERT, 
1024                 "GLUT event handler initialization failed ..." );
1025         exit(-1);
1026     }
1027
1028     // Init the user interface (we need to do this before passing off
1029     // control to glut and before fgInitGeneral to get our fonts !!!
1030     guiInit();
1031
1032     // First do some quick general initializations
1033     if( !fgInitGeneral()) {
1034         FG_LOG( FG_GENERAL, FG_ALERT, 
1035                 "General initializations failed ..." );
1036         exit(-1);
1037     }
1038
1039     // pass control off to the master GLUT event handler
1040     glutMainLoop();
1041
1042     // we never actually get here ... but just in case ... :-)
1043     return(0);
1044 }