1
0
Fork 0
flightgear/src/Main/main.cxx

2198 lines
67 KiB
C++
Raw Normal View History

// main.cxx -- top level sim routines
1998-04-21 17:02:27 +00:00
//
// Written by Curtis Olson for OpenGL, started May 1997.
//
// Copyright (C) 1997 - 1999 Curtis L. Olson - curt@flightgear.org
1998-04-21 17:02:27 +00:00
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
1998-04-21 17:02:27 +00:00
2001-07-12 17:55:44 +00:00
#include <simgear/compiler.h>
#include <simgear/misc/exception.hxx>
2001-07-12 17:55:44 +00:00
2001-03-23 22:42:49 +00:00
#ifdef SG_MATH_EXCEPTION_CLASH
# include <math.h>
#endif
1998-04-21 17:02:27 +00:00
#ifdef HAVE_WINDOWS_H
# include <windows.h>
# include <float.h>
1998-04-21 17:02:27 +00:00
#endif
#include <GL/glut.h>
#include <GL/gl.h>
2000-02-15 03:30:01 +00:00
1998-04-21 17:02:27 +00:00
#include <stdio.h>
#include <string.h>
#include <string>
1998-04-21 17:02:27 +00:00
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_SYS_STAT_H
2000-11-01 02:30:10 +00:00
# include <sys/stat.h> // for stat()
#endif
#ifdef HAVE_UNISTD_H
2000-11-01 02:30:10 +00:00
# include <unistd.h> // for stat()
#endif
// #ifdef HAVE_LIBX11
// # include <GL/glext.h>
// #endif
2001-05-23 20:54:51 +00:00
#include <plib/netChat.h>
2000-11-01 02:30:10 +00:00
#include <plib/pu.h>
#include <plib/ssg.h>
2000-02-15 03:30:01 +00:00
#include <simgear/constants.h> // for VERSION
2000-02-16 23:01:03 +00:00
#include <simgear/debug/logstream.hxx>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/sky/sky.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/timing/lowleveltime.h>
2000-02-15 03:30:01 +00:00
#include <Include/general.hxx>
1998-04-21 17:02:27 +00:00
1998-10-17 01:33:52 +00:00
#include <Aircraft/aircraft.hxx>
#include <Autopilot/newauto.hxx>
#include <Cockpit/cockpit.hxx>
#include <Cockpit/radiostack.hxx>
#include <Cockpit/steam.hxx>
2000-05-16 18:21:08 +00:00
#include <FDM/UIUCModel/uiuc_aircraftdir.h>
1998-06-12 14:27:25 +00:00
#include <GUI/gui.h>
#include <GUI/sgVec3Slider.hxx>
// #include <Joystick/joystick.hxx>
#ifdef FG_NETWORK_OLK
#include <NetworkOLK/network.h>
#endif
#include <Objects/matlib.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#ifdef ENABLE_AUDIO_SUPPORT
# include <Sound/soundmgr.hxx>
# include <Sound/morse.hxx>
#endif
#include <Time/event.hxx>
#include <Time/fg_timer.hxx>
#include <Time/light.hxx>
#include <Time/sunpos.hxx>
#include <Time/tmp.hxx>
#include <Input/input.hxx>
// ADA
#include <simgear/misc/sgstream.hxx>
#include <simgear/math/point3d.hxx>
#include <FDM/flight.hxx>
#include <FDM/ADA.hxx>
#include <Scenery/tileentry.hxx>
// Should already be inlcluded by gl.h if needed by your platform so
// we shouldn't include this here.
// #include <GL/glext.h>
// PFNGLPOINTPARAMETERFEXTPROC glPointParameterfEXT = 0;
// PFNGLPOINTPARAMETERFVEXTPROC glPointParameterfvEXT = 0;
float default_attenuation[3] = {1.0, 0.0, 0.0};
//Required for using GL_extensions
void fgLoadDCS (void);
void fgUpdateDCS (void);
ssgSelector *ship_sel=NULL;
// upto 32 instances of a same object can be loaded.
ssgTransform *ship_pos[32];
double obj_lat[32],obj_lon[32],obj_alt[32],obj_pitch[32],obj_roll[32];
int objc=0;
ssgSelector *lightpoints_brightness = new ssgSelector;
ssgTransform *lightpoints_transform = new ssgTransform;
FGTileEntry *dummy_tile;
sgVec3 rway_ols;
// ADA
#ifndef FG_OLD_WEATHER
# include <WeatherCM/FGLocalWeatherDatabase.h>
#else
# include <Weather/weather.hxx>
#endif
1998-04-21 17:02:27 +00:00
#include "version.h"
#include "fg_init.hxx"
1999-11-19 02:10:24 +00:00
#include "fg_io.hxx"
#include "fg_props.hxx"
#include "globals.hxx"
#include "splash.hxx"
#include "viewmgr.hxx"
2000-09-10 00:04:50 +00:00
#ifdef macintosh
# include <console.h> // -dw- for command line dialog
#endif
// This is a record containing a bit of global housekeeping information
FGGeneral general;
1998-04-21 17:02:27 +00:00
// Specify our current idle function state. This is used to run all
// our initializations out of the glutIdleLoop() so that we can get a
// splash screen up and running right away.
static int idle_state = 0;
2001-01-17 23:30:35 +00:00
static long global_multi_loop;
// attempt to avoid a large bounce at startup
static bool initial_freeze = true;
// forward declaration
void fgReshape( int width, int height );
// Global structures for the Audio library
#ifdef ENABLE_AUDIO_SUPPORT
static FGSimpleSound *s1;
static FGSimpleSound *s2;
#endif
// ssg variables
ssgRoot *scene = NULL;
ssgBranch *terrain = NULL;
// aircraft model stuff
ssgSelector *acmodel_selector = NULL;
ssgTransform *acmodel_pos = NULL;
ssgSelector *prop_selector = NULL;
ssgSelector *flaps_selector = NULL;
int acmodel_npropsettings;
int acmodel_proprpms[4][2]; // different propeller settings
ssgRoot *lighting = NULL;
ssgBranch *ground = NULL;
ssgBranch *airport = NULL;
#ifdef FG_NETWORK_OLK
ssgSelector *fgd_sel = NULL;
ssgTransform *fgd_pos = NULL;
#endif
// current fdm/position used for view
FGInterface cur_view_fdm;
// Sky structures
SGSky *thesky;
// hack
sgMat4 copy_of_ssgOpenGLAxisSwapMatrix =
{
{ 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f }
} ;
// The following defines flightgear options. Because glutlib will also
1998-04-21 17:02:27 +00:00
// want to parse its own options, those options must not be included here
// or they will get parsed by the main program option parser. Hence case
// is significant for any option added that might be in conflict with
// glutlib's parser.
//
// glutlib parses for:
// -display
// -direct (invalid in Win32)
// -geometry
// -gldebug
// -iconized
// -indirect (invalid in Win32)
// -synce
//
// Note that glutlib depends upon strings while this program's
// option parser wants only initial characters followed by numbers
// or pathnames.
//
ssgSimpleState *default_state;
ssgSimpleState *hud_and_panel;
ssgSimpleState *menus;
void fgBuildRenderStates( void ) {
default_state = new ssgSimpleState;
default_state->ref();
default_state->disable( GL_TEXTURE_2D );
default_state->enable( GL_CULL_FACE );
default_state->enable( GL_COLOR_MATERIAL );
default_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
default_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
default_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
default_state->disable( GL_BLEND );
default_state->disable( GL_ALPHA_TEST );
default_state->disable( GL_LIGHTING );
hud_and_panel = new ssgSimpleState;
hud_and_panel->ref();
hud_and_panel->disable( GL_CULL_FACE );
hud_and_panel->disable( GL_TEXTURE_2D );
hud_and_panel->disable( GL_LIGHTING );
hud_and_panel->enable( GL_BLEND );
menus = new ssgSimpleState;
menus->ref();
menus->disable( GL_CULL_FACE );
menus->disable( GL_TEXTURE_2D );
menus->enable( GL_BLEND );
}
// fgFindNode -- a function that finds a named node in an ssg graph
ssgEntity *fgFindNode( ssgEntity *node, const char *name ) {
if ( node->getName() != NULL && strcmp( name, node->getName() ) == 0 ) {
return node;
} else if ( node->isAKindOf( ssgTypeBranch() ) ) {
ssgEntity *kid = ((ssgBranch*)node)->getKid(0);
while (kid != NULL) {
ssgEntity *n = fgFindNode(kid, name);
if (n != NULL)
return n;
kid = ((ssgBranch*)node)->getNextKid();
}
}
return NULL;
}
1998-04-21 17:02:27 +00:00
// fgInitVisuals() -- Initialize various GL/view parameters
void fgInitVisuals( void ) {
fgLIGHT *l;
1998-04-21 17:02:27 +00:00
l = &cur_light_params;
#ifndef GLUT_WRONG_VERSION
// Go full screen if requested ...
if ( fgGetBool("/sim/startup/fullscreen") ) {
glutFullScreen();
}
#endif
1998-04-21 17:02:27 +00:00
// If enabled, normal vectors specified with glNormal are scaled
// to unit length after transformation. See glNormal.
2000-03-17 06:16:15 +00:00
// glEnable( GL_NORMALIZE );
1998-04-21 17:02:27 +00:00
2000-03-17 06:16:15 +00:00
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
1998-04-21 17:02:27 +00:00
sgVec3 sunpos;
sgSetVec3( sunpos, l->sun_vec[0], l->sun_vec[1], l->sun_vec[2] );
ssgGetLight( 0 ) -> setPosition( sunpos );
2000-03-17 06:16:15 +00:00
// glFogi (GL_FOG_MODE, GL_LINEAR);
glFogi (GL_FOG_MODE, GL_EXP2);
if ( (fgGetString("/sim/rendering/fog") == "disabled") ||
(!fgGetBool("/sim/rendering/shading"))) {
1998-06-13 00:40:32 +00:00
// if fastest fog requested, or if flat shading force fastest
2000-03-17 06:16:15 +00:00
glHint ( GL_FOG_HINT, GL_FASTEST );
} else if ( fgGetString("/sim/rendering/fog") == "nicest" ) {
2000-03-17 06:16:15 +00:00
glHint ( GL_FOG_HINT, GL_NICEST );
}
if ( fgGetBool("/sim/rendering/wireframe") ) {
// draw wire frame
2000-03-17 06:16:15 +00:00
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
}
// This is the default anyways, but it can't hurt
2000-03-17 06:16:15 +00:00
glFrontFace ( GL_CCW );
// Just testing ...
2000-03-17 06:16:15 +00:00
// glEnable(GL_POINT_SMOOTH);
// glEnable(GL_LINE_SMOOTH);
// glEnable(GL_POLYGON_SMOOTH);
1998-04-21 17:02:27 +00:00
}
// For HiRes screen Dumps using Brian Pauls TR Library
void trRenderFrame( void ) {
if ( fgPanelVisible() ) {
GLfloat height = fgGetInt("/sim/startup/ysize");
GLfloat view_h =
(current_panel->getViewHeight() - current_panel->getYOffset())
* (height / 768.0) + 1;
glTranslatef( 0.0, view_h, 0.0 );
}
static double m_log01 = -log( 0.01 );
static double sqrt_m_log01 = sqrt( m_log01 );
static GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
static GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
fgLIGHT *l = &cur_light_params;
glClearColor(l->adj_fog_color[0], l->adj_fog_color[1],
l->adj_fog_color[2], l->adj_fog_color[3]);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// set the opengl state to known default values
default_state->force();
// update fog params
double actual_visibility = thesky->get_visibility();
// GLfloat fog_exp_density = m_log01 / actual_visibility;
GLfloat fog_exp2_density = sqrt_m_log01 / actual_visibility;
GLfloat fog_exp2_punch_through = sqrt_m_log01 / ( actual_visibility * 1.5 );
glEnable( GL_FOG );
glFogf ( GL_FOG_DENSITY, fog_exp2_density);
glFogi ( GL_FOG_MODE, GL_EXP2 );
glFogfv ( GL_FOG_COLOR, l->adj_fog_color );
// GL_LIGHT_MODEL_AMBIENT has a default non-zero value so if
// we only update GL_AMBIENT for our lights we will never get
// a completely dark scene. So, we set GL_LIGHT_MODEL_AMBIENT
// explicitely to black.
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, black );
ssgGetLight( 0 ) -> setColour( GL_AMBIENT, l->scene_ambient );
// texture parameters
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
// we need a white diffuse light for the phase of the moon
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, white );
thesky->preDraw();
// draw the ssg scene
// return to the desired diffuse color
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
glEnable( GL_DEPTH_TEST );
ssgCullAndDraw( scene );
// draw the lights
glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
ssgCullAndDraw( lighting );
thesky->postDraw( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER );
// need to do this here as hud_and_panel state is static to
// main.cxx and HUD and Panel routines have to be called with
// knowledge of the the TR struct < see gui.cxx::HighResDump()
hud_and_panel->apply();
}
1998-04-21 17:02:27 +00:00
// Update all Visuals (redraws anything graphics related)
void fgRenderFrame( void ) {
// Update the default (kludged) properties.
fgUpdateProps();
2000-05-16 18:21:08 +00:00
fgLIGHT *l = &cur_light_params;
static double last_visibility = -9999;
2000-06-20 22:31:47 +00:00
static GLfloat fog_exp_density;
static GLfloat fog_exp2_density;
static GLfloat fog_exp2_punch_through;
// double angle;
// GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
// GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
// GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
// GLfloat mat_shininess[] = { 10.0 };
GLbitfield clear_mask;
if ( idle_state != 1000 ) {
// still initializing, draw the splash screen
if ( fgGetBool("/sim/startup/splash-screen") ) {
fgSplashUpdate(0.0);
}
} else {
// idle_state is now 1000 meaning we've finished all our
// initializations and are running the main loop, so this will
// now work without seg faulting the system.
1998-04-21 17:02:27 +00:00
// printf("Ground = %.2f Altitude = %.2f\n", scenery.cur_elev,
2001-03-24 04:56:46 +00:00
// FG_Altitude * SG_FEET_TO_METER);
// this is just a temporary hack, to make me understand Pui
// timerText -> setLabel (ctime (&t->cur_time));
// end of hack
1998-04-21 17:02:27 +00:00
// calculate our current position in cartesian space
scenery.center = scenery.next_center;
// printf("scenery center = %.2f %.2f %.2f\n", scenery.center.x(),
// scenery.center.y(), scenery.center.z());
FGViewerRPH *pilot_view =
(FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
pilot_view->set_geod_view_pos( cur_fdm_state->get_Longitude(),
cur_fdm_state->get_Lat_geocentric(),
cur_fdm_state->get_Altitude() *
2001-03-24 04:56:46 +00:00
SG_FEET_TO_METER );
pilot_view->set_sea_level_radius( cur_fdm_state->
get_Sea_level_radius() *
2001-03-24 04:56:46 +00:00
SG_FEET_TO_METER );
pilot_view->set_rph( cur_fdm_state->get_Phi(),
cur_fdm_state->get_Theta(),
cur_fdm_state->get_Psi() );
if (fgGetString("/sim/flight-model") == "ada") {
//+ve x is aft, +ve z is up (see viewer.hxx)
pilot_view->set_pilot_offset( -5.0, 0.0, 1.0 );
}
FGViewerLookAt *chase_view =
(FGViewerLookAt *)globals->get_viewmgr()->get_view( 1 );
sgVec3 po; // chase view pilot_offset
sgVec3 wup; // chase view world up
2001-05-18 20:30:36 +00:00
sgSetVec3( po, 0.0, 0.0, 100.0 );
2000-11-01 02:30:10 +00:00
sgCopyVec3( wup, pilot_view->get_world_up() );
sgMat4 CXFM; // chase view + pilot offset xform
sgMakeRotMat4( CXFM,
2001-03-24 04:48:44 +00:00
chase_view->get_view_offset() * SGD_RADIANS_TO_DEGREES -
cur_fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES,
wup );
sgVec3 npo; // new pilot offset after rotation
sgVec3 *pPO = PilotOffsetGet();
sgXformVec3( po, *pPO, pilot_view->get_UP() );
sgXformVec3( npo, po, CXFM );
chase_view->set_geod_view_pos( cur_fdm_state->get_Longitude(),
cur_fdm_state->get_Lat_geocentric(),
cur_fdm_state->get_Altitude() *
2001-03-24 04:56:46 +00:00
SG_FEET_TO_METER );
2000-11-01 02:30:10 +00:00
chase_view->set_sea_level_radius( cur_fdm_state->
get_Sea_level_radius() *
2001-03-24 04:56:46 +00:00
SG_FEET_TO_METER );
chase_view->set_pilot_offset( npo[0], npo[1], npo[2] );
chase_view->set_view_forward( pilot_view->get_view_pos() );
chase_view->set_view_up( wup );
2000-10-26 18:20:55 +00:00
#if 0
sgMat4 rph;
2000-11-01 02:30:10 +00:00
sgCopyMat4( rph, pilot_view->get_VIEW() );
cout << "RPH Matrix = " << endl;
int i, j;
for ( i = 0; i < 4; i++ ) {
for ( j = 0; j < 4; j++ ) {
printf("%10.4f ", rph[i][j]);
}
cout << endl;
}
2000-11-01 02:30:10 +00:00
sgMat4 la;
2000-11-01 02:30:10 +00:00
sgCopyMat4( la, chase_view->get_VIEW() );
cout << "LookAt Matrix = " << endl;
for ( i = 0; i < 4; i++ ) {
for ( j = 0; j < 4; j++ ) {
printf("%10.4f ", la[i][j]);
}
cout << endl;
}
2000-11-01 02:30:10 +00:00
#endif
// update view port
fgReshape( fgGetInt("/sim/startup/xsize"),
fgGetInt("/sim/startup/ysize") );
#if 0
// swing and a miss
if ( ! fgPanelVisible() ) {
xglViewport( 0, 0 ,
(GLint)(fgGetInt("/sim/startup/xsize")),
(GLint)(fgGetInt("/sim/startup/ysize")) );
} else {
int view_h =
int( (current_panel->getViewHeight() -
current_panel->getYOffset())
* (fgGetInt("/sim/startup/ysize") / 768.0) );
glViewport( 0,
(GLint)(fgGetInt("/sim/startup/ysize") - view_h),
(GLint)(fgGetInt("/sim/startup/xsize")),
(GLint)(view_h) );
}
#endif
1998-04-21 17:02:27 +00:00
// set the sun position
2000-03-17 06:16:15 +00:00
glLightfv( GL_LIGHT0, GL_POSITION, l->sun_vec );
clear_mask = GL_DEPTH_BUFFER_BIT;
if ( fgGetBool("/sim/rendering/wireframe") ) {
clear_mask |= GL_COLOR_BUFFER_BIT;
}
if ( fgGetBool("/sim/rendering/skyblend") ) {
if ( fgGetBool("/sim/rendering/textures") ) {
// glClearColor(black[0], black[1], black[2], black[3]);
glClearColor(l->adj_fog_color[0], l->adj_fog_color[1],
l->adj_fog_color[2], l->adj_fog_color[3]);
clear_mask |= GL_COLOR_BUFFER_BIT;
}
} else {
glClearColor(l->sky_color[0], l->sky_color[1],
l->sky_color[2], l->sky_color[3]);
clear_mask |= GL_COLOR_BUFFER_BIT;
}
2000-03-17 06:16:15 +00:00
glClear( clear_mask );
1998-04-21 17:02:27 +00:00
// Tell GL we are switching to model view parameters
// I really should create a derived ssg node or use a call
// back or something so that I can draw the sky within the
2000-06-20 02:29:31 +00:00
// ssgCullAndDraw() function, but for now I just mimic what
// ssg does to set up the model view matrix
2000-03-17 06:16:15 +00:00
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ssgSetCamera( (sgVec4 *)globals->get_current_view()->get_VIEW() );
// set the opengl state to known default values
default_state->force();
2000-06-20 22:31:47 +00:00
// update fog params if visibility has changed
#ifndef FG_OLD_WEATHER
thesky->set_visibility( WeatherDatabase->getWeatherVisibility() );
#else
thesky->set_visibility( current_weather.get_visibility() );
#endif
2001-03-24 04:56:46 +00:00
thesky->modify_vis( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
2000-06-20 22:31:47 +00:00
( global_multi_loop *
fgGetInt("/sim/speed-up") ) /
(double)fgGetInt("/sim/model-hz") );
2000-06-20 22:31:47 +00:00
double actual_visibility = thesky->get_visibility();
// cout << "actual visibility = " << actual_visibility << endl;
if ( actual_visibility != last_visibility ) {
last_visibility = actual_visibility;
// cout << "----> updating fog params" << endl;
// for GL_FOG_EXP
fog_exp_density = -log(0.01) / actual_visibility;
2000-06-20 22:31:47 +00:00
// for GL_FOG_EXP2
fog_exp2_density = sqrt( -log(0.01) ) / actual_visibility;
fog_exp2_punch_through = sqrt( -log(0.01) ) /
( actual_visibility * 1.5 );
2000-06-20 22:31:47 +00:00
}
// Set correct opengl fog density
glFogf (GL_FOG_DENSITY, fog_exp2_density);
2000-06-20 22:31:47 +00:00
// update the sky dome
if ( fgGetBool("/sim/rendering/skyblend") ) {
/* cout << "thesky->repaint() sky_color = "
<< cur_light_params.sky_color[0] << " "
<< cur_light_params.sky_color[1] << " "
<< cur_light_params.sky_color[2] << " "
<< cur_light_params.sky_color[3] << endl;
cout << " fog = "
<< cur_light_params.fog_color[0] << " "
<< cur_light_params.fog_color[1] << " "
<< cur_light_params.fog_color[2] << " "
<< cur_light_params.fog_color[3] << endl;
cout << " sun_angle = " << cur_light_params.sun_angle
<< " moon_angle = " << cur_light_params.moon_angle
<< endl; */
thesky->repaint( cur_light_params.sky_color,
2000-03-17 06:16:15 +00:00
cur_light_params.adj_fog_color,
cur_light_params.sun_angle,
cur_light_params.moon_angle,
2000-07-08 05:09:24 +00:00
globals->get_ephem()->getNumPlanets(),
globals->get_ephem()->getPlanets(),
globals->get_ephem()->getNumStars(),
globals->get_ephem()->getStars() );
/* cout << "thesky->reposition( view_pos = " << view_pos[0] << " "
<< view_pos[1] << " " << view_pos[2] << endl;
cout << " zero_elev = " << zero_elev[0] << " "
<< zero_elev[1] << " " << zero_elev[2]
<< " lon = " << cur_fdm_state->get_Longitude()
<< " lat = " << cur_fdm_state->get_Latitude() << endl;
cout << " sun_rot = " << cur_light_params.sun_rotation
<< " gst = " << SGTime::cur_time_params->getGst() << endl;
2000-07-08 05:09:24 +00:00
cout << " sun ra = " << globals->get_ephem()->getSunRightAscension()
<< " sun dec = " << globals->get_ephem()->getSunDeclination()
<< " moon ra = " << globals->get_ephem()->getMoonRightAscension()
<< " moon dec = " << globals->get_ephem()->getMoonDeclination() << endl; */
thesky->reposition( globals->get_current_view()->get_view_pos(),
globals->get_current_view()->get_zero_elev(),
globals->get_current_view()->get_world_up(),
cur_fdm_state->get_Longitude(),
cur_fdm_state->get_Latitude(),
2001-03-24 04:56:46 +00:00
cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
cur_light_params.sun_rotation,
2000-07-07 20:28:51 +00:00
globals->get_time_params()->getGst(),
2000-07-08 05:09:24 +00:00
globals->get_ephem()->getSunRightAscension(),
globals->get_ephem()->getSunDeclination(),
50000.0,
globals->get_ephem()->getMoonRightAscension(),
globals->get_ephem()->getMoonDeclination(),
50000.0 );
}
1998-04-21 17:02:27 +00:00
2000-03-17 06:16:15 +00:00
glEnable( GL_DEPTH_TEST );
2001-04-02 02:59:31 +00:00
if ( fgGetString("/sim/rendering/fog") != (string)"disabled" ) {
2000-03-17 06:16:15 +00:00
glEnable( GL_FOG );
glFogi( GL_FOG_MODE, GL_EXP2 );
glFogfv( GL_FOG_COLOR, l->adj_fog_color );
}
// set sun/lighting parameters
ssgGetLight( 0 ) -> setPosition( l->sun_vec );
// GL_LIGHT_MODEL_AMBIENT has a default non-zero value so if
// we only update GL_AMBIENT for our lights we will never get
// a completely dark scene. So, we set GL_LIGHT_MODEL_AMBIENT
// explicitely to black.
2000-06-20 04:50:00 +00:00
GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
2001-03-28 17:52:40 +00:00
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
2001-03-28 18:11:05 +00:00
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, black );
2001-03-28 18:11:05 +00:00
ssgGetLight( 0 ) -> setColour( GL_AMBIENT, l->scene_ambient );
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
// ssgGetLight( 0 ) -> setColour( GL_SPECULAR, l->scene_white );
// texture parameters
2000-03-17 06:16:15 +00:00
// glEnable( GL_TEXTURE_2D );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) ;
2000-03-17 06:16:15 +00:00
// glMatrixMode( GL_PROJECTION );
// glLoadIdentity();
float fov = globals->get_current_view()->get_fov();
ssgSetFOV(fov, fov * globals->get_current_view()->get_win_ratio());
1999-06-29 14:57:00 +00:00
2001-03-24 04:56:46 +00:00
double agl = current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER
1999-06-29 14:57:00 +00:00
- scenery.cur_elev;
2001-03-24 06:03:11 +00:00
// SG_LOG( SG_ALL, SG_INFO, "visibility is "
1999-06-29 17:26:46 +00:00
// << current_weather.get_visibility() );
1999-06-29 14:57:00 +00:00
if ( agl > 10.0 ) {
ssgSetNearFar( 10.0f, 120000.0f );
1999-06-29 14:57:00 +00:00
} else {
ssgSetNearFar( 0.5f, 120000.0f );
1999-06-29 14:57:00 +00:00
}
1999-06-19 04:48:07 +00:00
2000-11-01 02:30:10 +00:00
if ( globals->get_viewmgr()->get_current() == 0 ) {
// disable aircraft model
acmodel_selector->select(0);
2000-11-01 02:30:10 +00:00
} else {
// enable aircraft model and set up its position and orientation
acmodel_selector->select(1);
2000-11-01 02:30:10 +00:00
FGViewerRPH *pilot_view =
(FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
sgMat4 sgTRANS;
2000-11-01 02:30:10 +00:00
sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
1999-07-01 01:17:43 +00:00
sgVec3 ownship_up;
sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
sgMat4 sgROT;
sgMakeRotMat4( sgROT, -90.0, ownship_up );
// sgMat4 sgTMP;
// sgMat4 sgTUX;
// sgMultMat4( sgTMP, sgROT, pilot_view.VIEW_ROT );
// sgMultMat4( sgTUX, sgTMP, sgTRANS );
// sgTUX = ( sgROT * pilot_view.VIEW_ROT ) * sgTRANS
sgMat4 sgTUX;
sgCopyMat4( sgTUX, sgROT );
2000-11-01 02:30:10 +00:00
sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
sgPostMultMat4( sgTUX, sgTRANS );
sgCoord tuxpos;
sgSetCoord( &tuxpos, sgTUX );
acmodel_pos->setTransform( &tuxpos );
// set up moving parts
if (flaps_selector != NULL) {
flaps_selector->select( (globals->get_controls()->get_flaps() > 0.5f) ? 1 : 2 );
}
if (prop_selector != NULL) {
int propsel_mask = 0;
** Properties Renamed - /autopilot/locks/nav1 => /autopilot/locks/nav[0] - /autopilot/settings/altitude += "-ft" - /autopilot/settings/climb-rate += "-fpm" - /autopilot/settings/heading-bug += "-deg" - /consumables/fuel/tank1/level => /consumables/fuel/tank[0]/level-gal_us - /consumables/fuel/tank2/level => /consumables/fuel/tank[1]/level-gal_us - /engines/engine0/cht => /engines/engine[0]/cht-degf - /engines/engine0/egt => /engines/engine[0]/egt-degf - /engines/engine0/fuel-flow => /engines/engine[0]/fuel-flow-gph - /engines/engine0/mp => /engines/engine[0]/mp-osi - /engines/engine0/rpm => /engines/engine[0]/rpm - /environment/clouds/altitude += "-ft" - /environment/magnetic-dip += "-deg" - /environment/magnetic-varation += "-deg" - /environment/visibility += "-m" - /environment/wind-down += "-fps" - /environment/wind-east += "-fps" - /environment/wind-north += "-fps" - /orientation/heading += "-deg" - /orientation/heading-magnetic += "-deg" - /orientation/pitch += "-deg" - /orientation/roll += "-deg" - /position/altitude += "-ft" - /position/altitude-agl += "-ft" - /position/latitude += "-deg" - /position/longitude += "-deg" - /radios/adf/frequencies/selected += "-khz" - /radios/adf/frequencies/standby += "-khz" - /radios/adf/rotation += "-deg" - /radios/nav1/* => /radios/nav[0]/* - /radios/nav2/* => /radios/nav[1]/* - /radios/nav[*]/dme/distance += "-nm" - /radios/nav[*]/frequencies/selected += "-mhz" - /radios/nav[*]/frequencies/standby += "-mhz" - /radios/nav[*]/radials/actual += "-deg" - /radios/nav[*]/radials/selected += "-deg" - /sim/view/goal-offset += "-deg" - /sim/view/offset += "-deg" - /steam/adf += "-deg" - /steam/airspeed += "-kt" - /steam/altitude += "-ft" - /steam/gyro-compass += "-deg" - /steam/gyro-compass-error += "-deg" - /steam/mag-compass += "-deg" - /steam/vertical-speed += "-fpm" - /velocities/airspeed += "-kt" - /velocities/side-slip += "-rad" - /velocities/speed-down += "-fps" - /velocities/speed-east += "-fps" - /velocities/speed-north += "-fps" - /velocities/uBody += "-fps" - /velocities/vBody += "-fps" - /velocities/wBody += "-fps" - /velocities/vertical-speed += "-fps"
2001-07-02 22:27:24 +00:00
double rpm = fgGetDouble("/engines/engine[0]/rpm");
for (int i = 0; i < acmodel_npropsettings; i++) {
if (rpm >= acmodel_proprpms[i][0] &&
rpm <= acmodel_proprpms[i][1]) {
propsel_mask |= 1 << i;
}
}
prop_selector->select(propsel_mask);
}
}
// $$$ begin - added VS Renganthan 17 Oct 2K
fgUpdateDCS();
// $$$ end - added VS Renganthan 17 Oct 2K
# ifdef FG_NETWORK_OLK
if ( fgGetBool("/sim/networking/network-olk") ) {
sgCoord fgdpos;
other = head->next; /* put listpointer to start */
while ( other != tail) { /* display all except myself */
if ( strcmp( other->ipadr, fgd_mcp_ip) != 0) {
other->fgd_sel->select(1);
sgSetCoord( &fgdpos, other->sgFGD_COORD );
other->fgd_pos->setTransform( &fgdpos );
}
other = other->next;
}
// fgd_sel->select(1);
// sgCopyMat4( sgTUX, current_view.sgVIEW);
// sgCoord fgdpos;
// sgSetCoord( &fgdpos, sgFGD_VIEW );
// fgd_pos->setTransform( &fgdpos);
}
# endif
// position tile nodes and update range selectors
1999-06-30 00:25:13 +00:00
global_tile_mgr.prep_ssg_nodes();
if ( fgGetBool("/sim/rendering/skyblend") ) {
// draw the sky backdrop
2001-03-28 17:52:40 +00:00
// we need a white diffuse light for the phase of the moon
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, white );
thesky->preDraw();
2001-03-28 17:52:40 +00:00
// return to the desired diffuse color
ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse );
}
2000-06-20 02:29:31 +00:00
// draw the ssg scene
glEnable( GL_DEPTH_TEST );
ssgCullAndDraw( scene );
// change state for lighting here
// draw lighting
// Set punch through fog density
2000-12-04 22:35:10 +00:00
glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
#ifdef FG_EXPERIMENTAL_LIGHTING
// Enable states for drawing points with GL_extension
if (glutExtensionSupported("GL_EXT_point_parameters")) {
glEnable(GL_POINT_SMOOTH);
float quadratic[3] = {1.0, 0.01, 0.0001};
// get the address of our OpenGL extensions
glPointParameterfEXT = (PFNGLPOINTPARAMETERFEXTPROC)
wglGetProcAddress("glPointParameterfEXT");
glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC)
wglGetProcAddress("glPointParameterfvEXT");
// makes the points fade as they move away
glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, quadratic);
glPointParameterfEXT(GL_POINT_SIZE_MIN_EXT, 1.0);
glPointSize(4.0);
// Enable states for drawing runway lights with spherical mapping
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
//Maybe this is not the best way, but it works !!
glPolygonMode(GL_FRONT, GL_POINT);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
}
glDisable( GL_LIGHTING );
// blending function for runway lights
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
glEnable(GL_BLEND);
#endif
ssgCullAndDraw( lighting );
#ifdef FG_EXPERIMENTAL_LIGHTING
if (glutExtensionSupported("GL_EXT_point_parameters")) {
// Disable states used for runway lighting
glPolygonMode(GL_FRONT, GL_FILL);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT,
default_attenuation);
}
glPointSize(1.0);
#endif
if ( fgGetBool("/sim/rendering/skyblend") ) {
// draw the sky cloud layers
2001-03-24 04:56:46 +00:00
thesky->postDraw( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER );
}
// display HUD && Panel
2000-03-17 06:16:15 +00:00
glDisable( GL_FOG );
glDisable( GL_DEPTH_TEST );
// glDisable( GL_CULL_FACE );
// glDisable( GL_TEXTURE_2D );
// update the input subsystem
current_input.update();
// update the controls subsystem
globals->get_controls()->update();
hud_and_panel->apply();
fgCockpitUpdate();
// update the panel subsystem
if (current_panel != 0)
current_panel->update();
// We can do translucent menus, so why not. :-)
menus->apply();
2000-03-17 06:16:15 +00:00
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
puDisplay();
2000-03-17 06:16:15 +00:00
// glDisable ( GL_BLEND ) ;
2000-03-17 06:16:15 +00:00
// glEnable( GL_FOG );
}
1998-04-21 17:02:27 +00:00
2000-03-17 06:16:15 +00:00
glutSwapBuffers();
1998-04-21 17:02:27 +00:00
}
// Update internal time dependent calculations (i.e. flight model)
void fgUpdateTimeDepCalcs() {
2001-01-17 23:30:35 +00:00
static bool inited = false;
fgLIGHT *l = &cur_light_params;
1998-04-21 17:02:27 +00:00
int i;
2001-01-17 23:30:35 +00:00
long multi_loop = 1;
1998-04-21 17:02:27 +00:00
if ( !globals->get_freeze() && !initial_freeze ) {
// conceptually, this could be done for each fdm instance ...
2001-01-17 23:30:35 +00:00
if ( !inited ) {
cur_fdm_state->stamp();
inited = true;
}
SGTimeStamp current;
current.stamp();
long elapsed = current - cur_fdm_state->get_time_stamp();
cur_fdm_state->set_time_stamp( current );
elapsed += cur_fdm_state->get_remainder();
// cout << "elapsed = " << elapsed << endl;
// cout << "dt = " << cur_fdm_state->get_delta_t() << endl;
2001-01-17 23:30:35 +00:00
multi_loop = (long)(((double)elapsed * 0.000001) /
cur_fdm_state->get_delta_t() );
cur_fdm_state->set_multi_loop( multi_loop );
long remainder = elapsed - (long)( (multi_loop*1000000) *
cur_fdm_state->get_delta_t() );
cur_fdm_state->set_remainder( remainder );
2001-01-17 23:30:35 +00:00
// cout << "remainder = " << remainder << endl;
// chop max interations to something reasonable if the sim was
// delayed for an excesive amount of time
if ( multi_loop > 2.0 / cur_fdm_state->get_delta_t() ) {
multi_loop = (int)(2.0 / cur_fdm_state->get_delta_t());
cur_fdm_state->set_remainder( 0 );
}
// cout << "multi_loop = " << multi_loop << endl;
for ( i = 0; i < multi_loop * fgGetInt("/sim/speed-up"); ++i ) {
// run Autopilot system
current_autopilot->run();
// update autopilot
cur_fdm_state->update( 1 );
}
FGSteam::update( multi_loop * fgGetInt("/sim/speed-up") );
} else {
1999-10-11 23:09:07 +00:00
cur_fdm_state->update( 0 );
FGSteam::update( 0 );
//if ( global_tile_mgr.queue_size() == 0 ) {
initial_freeze = false;
//}
}
if ( fgGetString("/sim/view-mode") == "pilot" ) {
cur_view_fdm = *cur_fdm_state;
// do nothing
}
1998-04-21 17:02:27 +00:00
// update the view angle
FGViewer *v = globals->get_current_view();
1998-04-21 17:02:27 +00:00
for ( i = 0; i < multi_loop; i++ ) {
if ( fabs(v->get_goal_view_offset() - v->get_view_offset()) < 0.05 ) {
v->set_view_offset( v->get_goal_view_offset() );
1998-04-21 17:02:27 +00:00
break;
} else {
// move current_view.view_offset towards
// current_view.goal_view_offset
if ( v->get_goal_view_offset() > v->get_view_offset() )
{
2001-03-24 02:36:45 +00:00
if ( v->get_goal_view_offset() - v->get_view_offset() < SGD_PI ){
v->inc_view_offset( 0.01 );
1998-04-21 17:02:27 +00:00
} else {
v->inc_view_offset( -0.01 );
1998-04-21 17:02:27 +00:00
}
} else {
2001-03-24 02:36:45 +00:00
if ( v->get_view_offset() - v->get_goal_view_offset() < SGD_PI ){
v->inc_view_offset( -0.01 );
1998-04-21 17:02:27 +00:00
} else {
v->inc_view_offset( 0.01 );
1998-04-21 17:02:27 +00:00
}
}
2001-03-24 03:10:40 +00:00
if ( v->get_view_offset() > SGD_2PI ) {
v->inc_view_offset( -SGD_2PI );
} else if ( v->get_view_offset() < 0 ) {
2001-03-24 03:10:40 +00:00
v->inc_view_offset( SGD_2PI );
1998-04-21 17:02:27 +00:00
}
}
}
2001-03-24 02:36:45 +00:00
double tmp = -(l->sun_rotation + SGD_PI)
- (cur_fdm_state->get_Psi() -
globals->get_current_view()->get_view_offset() );
while ( tmp < 0.0 ) {
2001-03-24 03:10:40 +00:00
tmp += SGD_2PI;
}
2001-03-24 03:10:40 +00:00
while ( tmp > SGD_2PI ) {
tmp -= SGD_2PI;
}
/* printf("Psi = %.2f, viewoffset = %.2f sunrot = %.2f rottosun = %.2f\n",
2001-03-24 04:48:44 +00:00
FG_Psi * SGD_RADIANS_TO_DEGREES, current_view.view_offset * SGD_RADIANS_TO_DEGREES,
-(l->sun_rotation+SGD_PI) * SGD_RADIANS_TO_DEGREES, tmp * SGD_RADIANS_TO_DEGREES); */
l->UpdateAdjFog();
// Update solar system
2000-07-08 05:09:24 +00:00
globals->get_ephem()->update( globals->get_time_params()->getMjd(),
globals->get_time_params()->getLst(),
cur_fdm_state->get_Latitude() );
// Update radio stack model
current_radiostack->update();
1998-04-21 17:02:27 +00:00
}
void fgInitTimeDepCalcs( void ) {
// initialize timer
// #ifdef HAVE_SETITIMER
// fgTimerInit( 1.0 / fgGetInt("/sim/model-hz"),
1999-09-01 20:24:54 +00:00
// fgUpdateTimeDepCalcs );
// #endif HAVE_SETITIMER
1998-04-21 17:02:27 +00:00
}
1999-09-01 20:24:54 +00:00
static const double alt_adjust_ft = 3.758099;
2001-03-24 04:56:46 +00:00
static const double alt_adjust_m = alt_adjust_ft * SG_FEET_TO_METER;
1998-04-21 17:02:27 +00:00
1999-09-01 20:24:54 +00:00
// What should we do when we have nothing else to do? Let's get ready
// for the next move and update the display?
1998-04-21 17:02:27 +00:00
static void fgMainLoop( void ) {
static long remainder = 0;
long elapsed;
#ifdef FANCY_FRAME_COUNTER
int i;
double accum;
#else
1998-12-18 23:40:55 +00:00
static time_t last_time = 0;
static int frames = 0;
#endif // FANCY_FRAME_COUNTER
1998-04-21 17:02:27 +00:00
2000-07-07 20:28:51 +00:00
SGTime *t = globals->get_time_params();
1998-04-21 17:02:27 +00:00
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG, "Running Main Loop");
SG_LOG( SG_ALL, SG_DEBUG, "======= ==== ====");
#ifdef FG_NETWORK_OLK
if ( fgGetBool("/sim/networking/network-olk") ) {
if ( net_is_registered == 0 ) { // We first have to reg. to fgd
// printf("FGD: Netupdate\n");
fgd_send_com( "A", FGFS_host); // Send Mat4 data
fgd_send_com( "B", FGFS_host); // Recv Mat4 data
}
}
#endif
#if defined( ENABLE_PLIB_JOYSTICK )
1998-12-18 23:40:55 +00:00
// Read joystick and update control settings
// if ( fgGetString("/sim/control-mode") == "joystick" )
// {
// fgJoystickRead();
// }
1998-12-18 23:40:55 +00:00
#elif defined( ENABLE_GLUT_JOYSTICK )
// Glut joystick support works by feeding a joystick handler
// function to glut. This is taken care of once in the joystick
// init routine and we don't have to worry about it again.
#endif
#ifdef FG_OLD_WEATHER
current_weather.Update();
#endif
1998-10-02 12:46:43 +00:00
// Fix elevation. I'm just sticking this here for now, it should
// probably move eventually
/* printf("Before - ground = %.2f runway = %.2f alt = %.2f\n",
scenery.cur_elev,
2001-03-24 04:56:46 +00:00
cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
if ( scenery.cur_elev > -9990 ) {
2001-03-24 04:56:46 +00:00
if ( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER <
(scenery.cur_elev + alt_adjust_m - 3.0) ) {
// now set aircraft altitude above ground
printf("(*) Current Altitude = %.2f < %.2f forcing to %.2f\n",
2001-03-24 04:56:46 +00:00
cur_fdm_state->get_Altitude() * SG_FEET_TO_METER,
scenery.cur_elev + alt_adjust_m - 3.0,
scenery.cur_elev + alt_adjust_m );
fgFDMForceAltitude( fgGetString("/sim/flight-model"),
scenery.cur_elev + alt_adjust_m );
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG,
"<*> resetting altitude to "
2001-03-24 04:56:46 +00:00
<< cur_fdm_state->get_Altitude() * SG_FEET_TO_METER
<< " meters" );
}
}
/* printf("Adjustment - ground = %.2f runway = %.2f alt = %.2f\n",
scenery.cur_elev,
2001-03-24 04:56:46 +00:00
cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
// cout << "Warp = " << globals->get_warp() << endl;
1998-04-21 17:02:27 +00:00
// update "time"
if ( globals->get_warp_delta() != 0 ) {
globals->inc_warp( globals->get_warp_delta() );
}
2000-03-29 00:15:58 +00:00
t->update( cur_fdm_state->get_Longitude(),
cur_fdm_state->get_Latitude(),
globals->get_warp() );
1998-04-21 17:02:27 +00:00
if ( globals->get_warp_delta() != 0 ) {
fgUpdateSkyAndLightingParams();
}
// update magvar model
globals->get_mag()->update( cur_fdm_state->get_Longitude(),
cur_fdm_state->get_Latitude(),
2001-03-24 04:56:46 +00:00
cur_fdm_state->get_Altitude()* SG_FEET_TO_METER,
globals->get_time_params()->getJD() );
// Get elapsed time (in usec) for this past frame
1998-04-21 17:02:27 +00:00
elapsed = fgGetTimeInterval();
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG,
"Elapsed time interval is = " << elapsed
<< ", previous remainder is = " << remainder );
// Calculate frame rate average
#ifdef FANCY_FRAME_COUNTER
/* old fps calculation */
if ( elapsed > 0 ) {
double tmp;
accum = 0.0;
for ( i = FG_FRAME_RATE_HISTORY - 2; i >= 0; i-- ) {
tmp = general.get_frame(i);
accum += tmp;
// printf("frame[%d] = %.2f\n", i, g->frames[i]);
general.set_frame(i+1,tmp);
}
tmp = 1000000.0 / (float)elapsed;
general.set_frame(0,tmp);
// printf("frame[0] = %.2f\n", general.frames[0]);
accum += tmp;
general.set_frame_rate(accum / (float)FG_FRAME_RATE_HISTORY);
// printf("ave = %.2f\n", general.frame_rate);
}
#else
if ( (t->get_cur_time() != last_time) && (last_time > 0) ) {
general.set_frame_rate( frames );
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG,
"--> Frame rate is = " << general.get_frame_rate() );
1998-12-18 23:40:55 +00:00
frames = 0;
}
last_time = t->get_cur_time();
1998-12-18 23:40:55 +00:00
++frames;
#endif
1998-04-21 17:02:27 +00:00
// Run flight model
// Calculate model iterations needed for next frame
elapsed += remainder;
2001-01-17 23:30:35 +00:00
global_multi_loop = (long)(((double)elapsed * 0.000001) *
fgGetInt("/sim/model-hz"));
remainder = elapsed - ( (global_multi_loop*1000000) /
fgGetInt("/sim/model-hz") );
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG,
"Model iterations needed = " << global_multi_loop
<< ", new remainder = " << remainder );
1998-12-18 23:40:55 +00:00
2001-01-17 23:30:35 +00:00
// chop max interations to something reasonable if the sim was
// delayed for an excesive amount of time
if ( global_multi_loop > 2.0 * fgGetInt("/sim/model-hz") ) {
global_multi_loop = (int)(2.0 * fgGetInt("/sim/model-hz") );
remainder = 0;
}
// flight model
if ( global_multi_loop > 0 ) {
fgUpdateTimeDepCalcs();
} else {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG,
"Elapsed time is zero ... we're zinging" );
1998-04-21 17:02:27 +00:00
}
2000-09-10 00:04:50 +00:00
#if ! defined( macintosh )
1999-11-19 02:10:24 +00:00
// Do any I/O channel work that might need to be done
fgIOProcess();
#endif
1998-04-21 17:02:27 +00:00
// see if we need to load any new scenery tiles
2001-03-30 01:04:50 +00:00
global_tile_mgr.update( cur_fdm_state->get_Longitude()
* SGD_RADIANS_TO_DEGREES,
cur_fdm_state->get_Latitude()
* SGD_RADIANS_TO_DEGREES );
1998-04-21 17:02:27 +00:00
// see if we need to load any deferred-load textures
material_lib.load_next_deferred();
1998-04-21 17:02:27 +00:00
// Process/manage pending events
global_events.Process();
1998-04-21 17:02:27 +00:00
// Run audio scheduler
#ifdef ENABLE_AUDIO_SUPPORT
static bool bCranking;
if ( fgGetBool("/sim/sound") && globals->get_soundmgr()->is_working() ) {
if ( fgGetString("/sim/aircraft") == "c172" ) {
if(fgGetBool("/engines/engine[0]/running")) {
// pitch corresponds to rpm
// volume corresponds to manifold pressure
// cout << "AUDIO working = "
// << globals->get_soundmgr()->is_working() << endl;
double rpm_factor;
if ( cur_fdm_state->get_engine(0) != NULL ) {
rpm_factor = cur_fdm_state->get_engine(0)->get_RPM() / 2500.0;
} else {
rpm_factor = 1.0;
}
// cout << "rpm = " << cur_fdm_state->get_engine(0)->get_RPM()
// << endl;
double pitch = 0.3 + rpm_factor * 3.0;
// don't run at absurdly slow rates -- not realistic
// and sounds bad to boot. :-)
if (pitch < 0.7) { pitch = 0.7; }
if (pitch > 5.0) { pitch = 5.0; }
double mp_factor;
if ( cur_fdm_state->get_engine(0) != NULL ) {
mp_factor = cur_fdm_state->get_engine(0)->get_Manifold_Pressure() / 100;
} else {
mp_factor = 0.3;
}
/* cout << "mp = "
<< cur_fdm_state->get_engine(0)->get_Manifold_Pressure()
<< endl; */
double volume = 0.15 + mp_factor / 2.0;
if ( volume < 0.15 ) { volume = 0.15; }
if ( volume > 0.5 ) { volume = 0.5; }
// cout << "volume = " << volume << endl;
s1->set_pitch( pitch );
s1->set_volume( volume );
} else {
s1->set_pitch(0.0);
s1->set_volume(0.0);
}
if(fgGetBool("/engines/engine[0]/cranking")) {
if(!bCranking) {
globals->get_soundmgr()->play_looped("cranking");
bCranking = true;
}
} else {
if(bCranking) {
globals->get_soundmgr()->stop("cranking");
bCranking = false;
}
}
} else { // Not C172
double param
= globals->get_controls()->get_throttle( 0 ) * 2.0 + 1.0;
s1->set_pitch( param );
s1->set_volume( param );
2000-10-02 23:07:30 +00:00
}
globals->get_soundmgr()->update();
}
#endif
1998-04-21 17:02:27 +00:00
// redraw display
fgRenderFrame();
2001-03-24 06:03:11 +00:00
SG_LOG( SG_ALL, SG_DEBUG, "" );
1998-04-21 17:02:27 +00:00
}
// This is the top level master main function that is registered as
// our idle funciton
//
// The first few passes take care of initialization things (a couple
// per pass) and once everything has been initialized fgMainLoop from
// then on.
static void fgIdleFunction ( void ) {
// printf("idle state == %d\n", idle_state);
if ( idle_state == 0 ) {
// Initialize the splash screen right away
if ( fgGetBool("/sim/startup/splash-screen") ) {
fgSplashInit();
}
idle_state++;
} else if ( idle_state == 1 ) {
// Initialize audio support
#ifdef ENABLE_AUDIO_SUPPORT
// Start the intro music
#if !defined(WIN32)
if ( fgGetBool("/sim/startup/intro-music") ) {
SGPath mp3file( globals->get_fg_root() );
mp3file.append( "Sounds/intro.mp3" );
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO,
"Starting intro music: " << mp3file.str() );
string command = "mpg123 " + mp3file.str() + "> /dev/null 2>&1";
system ( command.c_str() );
}
#endif // !WIN32
FGSoundMgr *soundmgr = new FGSoundMgr;
globals->set_soundmgr( soundmgr );
if ( fgGetBool("/sim/sound") ) {
globals->get_soundmgr()->init();
s1 = new FGSimpleSound( fgGetString("/sim/sounds/engine",
"Sounds/wasp.wav") );
globals->get_soundmgr()->add( s1, "engine loop" );
globals->get_soundmgr()->play_looped( "engine loop" );
SG_LOG( SG_GENERAL, SG_INFO,
"Rate = " << s1->get_sample()->getRate()
<< " Bps = " << s1->get_sample()->getBps()
<< " Stereo = " << s1->get_sample()->getStereo() );
// s2 = new FGSimpleSound( "Sounds/corflaps.wav" );
// s2->set_volume( 0.3 );
// globals->get_soundmgr()->add( s2, "flaps" );
s2 = new FGSimpleSound( fgGetString("/sim/sounds/engine",
"Sounds/cranking.wav") );
globals->get_soundmgr()->add( s2, "cranking" );
s2->set_pitch(1.5);
s2->set_volume(0.25);
}
#endif
idle_state++;
} else if ( idle_state == 2 ) {
// These are a few miscellaneous things that aren't really
// "subsystems" but still need to be initialized.
#ifdef USE_GLIDE
if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
grTexLodBiasValue ( GR_TMU0, 1.0 ) ;
}
#endif
idle_state++;
} else if ( idle_state == 3 ) {
// This is the top level init routine which calls all the
// other subsystem initialization routines. If you are adding
// a subsystem to flightgear, its initialization call should
// located in this routine.
if( !fgInitSubsystems()) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT,
"Subsystem initializations failed ..." );
exit(-1);
}
idle_state++;
} else if ( idle_state == 4 ) {
// setup OpenGL view parameters
fgInitVisuals();
idle_state++;
} else if ( idle_state == 5 ) {
idle_state++;
} else if ( idle_state == 6 ) {
// sleep(1);
idle_state = 1000;
cout << "Panel visible = " << fgPanelVisible() << endl;
fgReshape( fgGetInt("/sim/startup/xsize"),
fgGetInt("/sim/startup/ysize") );
}
if ( idle_state == 1000 ) {
// We've finished all our initialization steps, from now on we
// run the main loop.
fgMainLoop();
} else {
if ( fgGetBool("/sim/startup/splash-screen") ) {
fgSplashUpdate(0.0);
}
}
}
1999-05-06 22:16:12 +00:00
// options.cxx needs to see this for toggle_panel()
1998-04-21 17:02:27 +00:00
// Handle new window size or exposure
1999-05-06 22:16:12 +00:00
void fgReshape( int width, int height ) {
// for all views
for ( int i = 0; i < globals->get_viewmgr()->size(); ++i ) {
if ( ! fgPanelVisible() || idle_state != 1000 ) {
globals->get_viewmgr()->get_view(i)->
set_win_ratio( (float)height / (float)width );
} else {
int view_h =
int((current_panel->getViewHeight() -
current_panel->getYOffset())
* (height / 768.0)) + 1;
globals->get_viewmgr()->get_view(i)->
set_win_ratio( (float)view_h / (float)width );
}
}
if ( ! fgPanelVisible() || idle_state != 1000 ) {
2000-03-17 06:16:15 +00:00
glViewport(0, 0 , (GLint)(width), (GLint)(height) );
} else {
David Megginson writes: I have a scrollable panel working (it didn't take long in the end). A panel can now be much wider or higher than the available area, and the user can scroll around using [Shift]F5, [Shift]F6, [Shift]F7, and [Shift]F8. The user can also scroll the panel down to get a bigger external view. Mouse clicks seem still to be working correctly. To set the panel's (virtual) height and width, use the panel file's /w and /h properties in a panel XML file; to set the initial x- and y- offsets (untested), use the panel file's /x-offset and /y-offset properties; to set the initial height of the external view (untested and optional), use the panel file's /view-height property. Note that none of these show up in the regular FGFS property manager. Unfortunately, these patches will not affect your initialization problems with the property manager -- I'm having a hard time tracking them down because I cannot reproduce them. I have also made some patches to main.cxx and views.cxx to do two things: 1. Expand or shrink the external view as the panel moves up and down. 2. Set the window ratio correctly, so that we don't get an oval sun and flat clouds when the panel is visible (the problem before was integer division, so I added casts). Unfortunately, the window ratio is not set properly at start-up -- there are too many dependencies, and I haven't figured that part out yet. As soon as you hide and redisplay the panel or move it vertically (i.e. force fgReshape to be called), you'll see the correct ratio.
2000-10-06 21:16:01 +00:00
int view_h =
int((current_panel->getViewHeight() - current_panel->getYOffset())
* (height / 768.0)) + 1;
David Megginson writes: I have a scrollable panel working (it didn't take long in the end). A panel can now be much wider or higher than the available area, and the user can scroll around using [Shift]F5, [Shift]F6, [Shift]F7, and [Shift]F8. The user can also scroll the panel down to get a bigger external view. Mouse clicks seem still to be working correctly. To set the panel's (virtual) height and width, use the panel file's /w and /h properties in a panel XML file; to set the initial x- and y- offsets (untested), use the panel file's /x-offset and /y-offset properties; to set the initial height of the external view (untested and optional), use the panel file's /view-height property. Note that none of these show up in the regular FGFS property manager. Unfortunately, these patches will not affect your initialization problems with the property manager -- I'm having a hard time tracking them down because I cannot reproduce them. I have also made some patches to main.cxx and views.cxx to do two things: 1. Expand or shrink the external view as the panel moves up and down. 2. Set the window ratio correctly, so that we don't get an oval sun and flat clouds when the panel is visible (the problem before was integer division, so I added casts). Unfortunately, the window ratio is not set properly at start-up -- there are too many dependencies, and I haven't figured that part out yet. As soon as you hide and redisplay the panel or move it vertically (i.e. force fgReshape to be called), you'll see the correct ratio.
2000-10-06 21:16:01 +00:00
glViewport(0, (GLint)(height - view_h),
(GLint)(width), (GLint)(view_h) );
1998-04-21 17:02:27 +00:00
}
fgSetInt("/sim/startup/xsize", width);
fgSetInt("/sim/startup/ysize", height);
1999-09-28 22:43:52 +00:00
float fov = globals->get_current_view()->get_fov();
ssgSetFOV(fov, fov * globals->get_current_view()->get_win_ratio());
1999-08-31 23:22:05 +00:00
2000-05-13 00:02:43 +00:00
fgHUDReshape();
1998-04-21 17:02:27 +00:00
}
// Initialize GLUT and define a main window
int fgGlutInit( int *argc, char **argv ) {
2000-09-10 00:04:50 +00:00
#if !defined( macintosh )
// GLUT will extract all glut specific options so later on we only
// need wory about our own.
2000-03-17 06:16:15 +00:00
glutInit(argc, argv);
#endif
1998-04-21 17:02:27 +00:00
// Define Display Parameters
2000-03-17 06:16:15 +00:00
glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
1998-04-21 17:02:27 +00:00
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO, "Opening a window: " <<
fgGetInt("/sim/startup/xsize") << "x"
<< fgGetInt("/sim/startup/ysize") );
1998-04-21 17:02:27 +00:00
// Define initial window size
glutInitWindowSize( fgGetInt("/sim/startup/xsize"),
fgGetInt("/sim/startup/ysize") );
1998-04-21 17:02:27 +00:00
// Initialize windows
if ( !fgGetBool("/sim/startup/game-mode")) {
1998-08-20 15:10:33 +00:00
// Open the regular window
glutCreateWindow("FlightGear");
#ifndef GLUT_WRONG_VERSION
1998-08-20 15:10:33 +00:00
} else {
// Open the cool new 'game mode' window
char game_mode_str[256];
2000-05-13 00:02:43 +00:00
sprintf( game_mode_str, "width=%d height=%d bpp=%d",
fgGetInt("/sim/startup/xsize"),
fgGetInt("/sim/startup/ysize"),
fgGetInt("/sim/rendering/bits-per-pixel"));
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO,
"game mode params = " << game_mode_str );
glutGameModeString( game_mode_str );
1998-08-20 15:10:33 +00:00
glutEnterGameMode();
#endif
1998-08-20 15:10:33 +00:00
}
1998-04-21 17:02:27 +00:00
// This seems to be the absolute earliest in the init sequence
// that these calls will return valid info. Too bad it's after
// we've already created and sized out window. :-(
general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO, general.get_glRenderer() );
GLint tmp;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &tmp );
general.set_glMaxTexSize( tmp );
2001-03-24 06:03:11 +00:00
SG_LOG ( SG_GENERAL, SG_INFO, "Max texture size = " << tmp );
glGetIntegerv( GL_DEPTH_BITS, &tmp );
general.set_glDepthBits( tmp );
2001-03-24 06:03:11 +00:00
SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp );
return 1;
}
1998-04-21 17:02:27 +00:00
// Initialize GLUT event handlers
int fgGlutInitEvents( void ) {
// call fgReshape() on window resizes
2000-03-17 06:16:15 +00:00
glutReshapeFunc( fgReshape );
1998-04-21 17:02:27 +00:00
// call GLUTkey() on keyboard event
glutKeyboardFunc(GLUTkey);
glutKeyboardUpFunc(GLUTkeyup);
glutSpecialFunc(GLUTspecialkey);
glutSpecialUpFunc(GLUTspecialkeyup);
1998-04-21 17:02:27 +00:00
// call guiMouseFunc() whenever our little rodent is used
glutMouseFunc ( guiMouseFunc );
glutMotionFunc (guiMotionFunc );
glutPassiveMotionFunc (guiMotionFunc );
// call fgMainLoop() whenever there is
// nothing else to do
2000-03-17 06:16:15 +00:00
glutIdleFunc( fgIdleFunction );
1998-04-21 17:02:27 +00:00
// draw the scene
2000-03-17 06:16:15 +00:00
glutDisplayFunc( fgRenderFrame );
1998-04-21 17:02:27 +00:00
return(1);
}
1998-04-21 17:02:27 +00:00
// Main loop
int mainLoop( int argc, char **argv ) {
2000-09-10 00:04:50 +00:00
#if defined( macintosh )
2000-04-27 21:57:08 +00:00
freopen ("stdout.txt", "w", stdout );
freopen ("stderr.txt", "w", stderr );
argc = ccommand( &argv );
#endif
#ifdef HAVE_BC5PLUS
_control87(MCW_EM, MCW_EM); /* defined in float.h */
#endif
// set default log levels
2001-03-24 06:03:11 +00:00
sglog().setLogLevels( SG_ALL, SG_INFO );
string version;
#ifdef FLIGHTGEAR_VERSION
version = FLIGHTGEAR_VERSION;
#else
version = "unknown version";
#endif
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO, "FlightGear: Version "
<< version << endl );
// Allocate global data structures. This needs to happen before
// we parse command line options
globals = new FGGlobals;
// seed the random number generater
sg_srandom_time();
SGRoute *route = new SGRoute;
globals->set_route( route );
FGControls *controls = new FGControls;
globals->set_controls( controls );
FGViewMgr *viewmgr = new FGViewMgr;
globals->set_viewmgr( viewmgr );
FGViewerRPH *pv = new FGViewerRPH;
globals->get_viewmgr()->add_view( pv );
FGViewerLookAt *chase = new FGViewerLookAt;
globals->get_viewmgr()->add_view( chase );
string_list *col = new string_list;
globals->set_channel_options_list( col );
// set current view to 0 (first) which is our main pilot view
globals->set_current_view( globals->get_viewmgr()->get_view( 0 ) );
// Scan the config file(s) and command line options to see if
// fg_root was specified (ignore all other options for now)
fgInitFGRoot(argc, argv);
// Check for the correct base package version
string base_version = fgBasePackageVersion();
if ( !(base_version == "0.7.9") ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Base package check failed ... "
2001-07-16 19:37:13 +00:00
<< "Found version " << base_version );
SG_LOG( SG_GENERAL, SG_ALERT, "Please upgrade to version 0.7.9" );
exit(-1);
}
// Initialize the Aircraft directory to "" (UIUC)
aircraft_dir = "";
// Load the configuration parameters
if ( !fgInitConfig(argc, argv) ) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
exit(-1);
}
1998-08-20 15:10:33 +00:00
// Initialize the Window/Graphics environment.
if( !fgGlutInit(&argc, argv) ) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT, "GLUT initialization failed ..." );
exit(-1);
1998-08-20 15:10:33 +00:00
}
// Initialize the various GLUT Event Handlers.
if( !fgGlutInitEvents() ) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT,
"GLUT event handler initialization failed ..." );
exit(-1);
1998-08-20 15:10:33 +00:00
}
// Initialize plib net interface
netInit( &argc, argv );
// Initialize ssg (from plib). Needs to come before we do any
// other ssg stuff, but after opengl/glut has been initialized.
ssgInit();
1998-08-20 15:10:33 +00:00
// Initialize the user interface (we need to do this before
// passing off control to glut and before fgInitGeneral to get our
// fonts !!!
guiInit();
2001-05-23 20:54:51 +00:00
#ifdef GL_EXT_texture_lod_bias
glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, -0.5 ) ;
#endif
#if 0
#ifdef GL_EXT_texture_filter_anisotropic
float max_anisotropy;
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
max_anisotropy );
cout << "Max anisotropy = " << max_anisotropy << endl;
#endif
#endif
// set current_options lon/lat if an airport id is specified
// cout << "3. airport_id = " << fgGetString("/sim/startup/airport-id") << endl;
if ( fgGetString("/sim/startup/airport-id").length() ) {
// fgSetPosFromAirportID( fgGetString("/sim/startup/airport-id") );
fgSetPosFromAirportIDandHdg( fgGetString("/sim/startup/airport-id"),
** Properties Renamed - /autopilot/locks/nav1 => /autopilot/locks/nav[0] - /autopilot/settings/altitude += "-ft" - /autopilot/settings/climb-rate += "-fpm" - /autopilot/settings/heading-bug += "-deg" - /consumables/fuel/tank1/level => /consumables/fuel/tank[0]/level-gal_us - /consumables/fuel/tank2/level => /consumables/fuel/tank[1]/level-gal_us - /engines/engine0/cht => /engines/engine[0]/cht-degf - /engines/engine0/egt => /engines/engine[0]/egt-degf - /engines/engine0/fuel-flow => /engines/engine[0]/fuel-flow-gph - /engines/engine0/mp => /engines/engine[0]/mp-osi - /engines/engine0/rpm => /engines/engine[0]/rpm - /environment/clouds/altitude += "-ft" - /environment/magnetic-dip += "-deg" - /environment/magnetic-varation += "-deg" - /environment/visibility += "-m" - /environment/wind-down += "-fps" - /environment/wind-east += "-fps" - /environment/wind-north += "-fps" - /orientation/heading += "-deg" - /orientation/heading-magnetic += "-deg" - /orientation/pitch += "-deg" - /orientation/roll += "-deg" - /position/altitude += "-ft" - /position/altitude-agl += "-ft" - /position/latitude += "-deg" - /position/longitude += "-deg" - /radios/adf/frequencies/selected += "-khz" - /radios/adf/frequencies/standby += "-khz" - /radios/adf/rotation += "-deg" - /radios/nav1/* => /radios/nav[0]/* - /radios/nav2/* => /radios/nav[1]/* - /radios/nav[*]/dme/distance += "-nm" - /radios/nav[*]/frequencies/selected += "-mhz" - /radios/nav[*]/frequencies/standby += "-mhz" - /radios/nav[*]/radials/actual += "-deg" - /radios/nav[*]/radials/selected += "-deg" - /sim/view/goal-offset += "-deg" - /sim/view/offset += "-deg" - /steam/adf += "-deg" - /steam/airspeed += "-kt" - /steam/altitude += "-ft" - /steam/gyro-compass += "-deg" - /steam/gyro-compass-error += "-deg" - /steam/mag-compass += "-deg" - /steam/vertical-speed += "-fpm" - /velocities/airspeed += "-kt" - /velocities/side-slip += "-rad" - /velocities/speed-down += "-fps" - /velocities/speed-east += "-fps" - /velocities/speed-north += "-fps" - /velocities/uBody += "-fps" - /velocities/vBody += "-fps" - /velocities/wBody += "-fps" - /velocities/vertical-speed += "-fps"
2001-07-02 22:27:24 +00:00
fgGetDouble("/orientation/heading-deg") );
}
// Initialize time
SGPath zone( globals->get_fg_root() );
2000-07-07 23:56:43 +00:00
zone.append( "Timezone" );
** Properties Renamed - /autopilot/locks/nav1 => /autopilot/locks/nav[0] - /autopilot/settings/altitude += "-ft" - /autopilot/settings/climb-rate += "-fpm" - /autopilot/settings/heading-bug += "-deg" - /consumables/fuel/tank1/level => /consumables/fuel/tank[0]/level-gal_us - /consumables/fuel/tank2/level => /consumables/fuel/tank[1]/level-gal_us - /engines/engine0/cht => /engines/engine[0]/cht-degf - /engines/engine0/egt => /engines/engine[0]/egt-degf - /engines/engine0/fuel-flow => /engines/engine[0]/fuel-flow-gph - /engines/engine0/mp => /engines/engine[0]/mp-osi - /engines/engine0/rpm => /engines/engine[0]/rpm - /environment/clouds/altitude += "-ft" - /environment/magnetic-dip += "-deg" - /environment/magnetic-varation += "-deg" - /environment/visibility += "-m" - /environment/wind-down += "-fps" - /environment/wind-east += "-fps" - /environment/wind-north += "-fps" - /orientation/heading += "-deg" - /orientation/heading-magnetic += "-deg" - /orientation/pitch += "-deg" - /orientation/roll += "-deg" - /position/altitude += "-ft" - /position/altitude-agl += "-ft" - /position/latitude += "-deg" - /position/longitude += "-deg" - /radios/adf/frequencies/selected += "-khz" - /radios/adf/frequencies/standby += "-khz" - /radios/adf/rotation += "-deg" - /radios/nav1/* => /radios/nav[0]/* - /radios/nav2/* => /radios/nav[1]/* - /radios/nav[*]/dme/distance += "-nm" - /radios/nav[*]/frequencies/selected += "-mhz" - /radios/nav[*]/frequencies/standby += "-mhz" - /radios/nav[*]/radials/actual += "-deg" - /radios/nav[*]/radials/selected += "-deg" - /sim/view/goal-offset += "-deg" - /sim/view/offset += "-deg" - /steam/adf += "-deg" - /steam/airspeed += "-kt" - /steam/altitude += "-ft" - /steam/gyro-compass += "-deg" - /steam/gyro-compass-error += "-deg" - /steam/mag-compass += "-deg" - /steam/vertical-speed += "-fpm" - /velocities/airspeed += "-kt" - /velocities/side-slip += "-rad" - /velocities/speed-down += "-fps" - /velocities/speed-east += "-fps" - /velocities/speed-north += "-fps" - /velocities/uBody += "-fps" - /velocities/vBody += "-fps" - /velocities/wBody += "-fps" - /velocities/vertical-speed += "-fps"
2001-07-02 22:27:24 +00:00
SGTime *t = new SGTime( fgGetDouble("/position/longitude-deg") * SGD_DEGREES_TO_RADIANS,
fgGetDouble("/position/latitude-deg") * SGD_DEGREES_TO_RADIANS,
2000-07-22 23:34:28 +00:00
zone.str() );
2000-07-07 20:28:51 +00:00
// Handle potential user specified time offsets
time_t cur_time = t->get_cur_time();
2000-07-07 23:56:43 +00:00
time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
2000-07-07 20:28:51 +00:00
time_t aircraftLocalTime =
2000-07-07 23:56:43 +00:00
sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
// Okay, we now have six possible scenarios
int offset = fgGetInt("/sim/startup/time-offset");
const string &offset_type = fgGetString("/sim/startup/time-offset-type");
if (offset_type == "system-offset") {
globals->set_warp( offset );
} else if (offset_type == "gmt-offset") {
globals->set_warp( offset - (currGMT - systemLocalTime) );
} else if (offset_type == "latitude-offset") {
globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) );
} else if (offset_type == "system") {
globals->set_warp( offset - cur_time );
} else if (offset_type == "gmt") {
globals->set_warp( offset - currGMT );
} else if (offset_type == "latitude") {
globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) -
cur_time );
} else {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT,
"Unsupported offset type " << offset_type );
exit( -1 );
}
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO, "After time init, warp = "
<< globals->get_warp() );
globals->set_warp_delta( 0 );
2000-07-07 23:56:43 +00:00
t->update( 0.0, 0.0, globals->get_warp() );
2000-07-07 20:28:51 +00:00
globals->set_time_params( t );
// Do some quick general initializations
if( !fgInitGeneral()) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_ALERT,
"General initializations failed ..." );
exit(-1);
}
SGPath modelpath( globals->get_fg_root() );
1999-07-01 01:17:43 +00:00
ssgModelPath( (char *)modelpath.c_str() );
2001-01-08 22:01:24 +00:00
// Scene graph root
scene = new ssgRoot;
scene->setName( "Scene" );
lighting = new ssgRoot;
lighting->setName( "Lighting" );
// Initialize the sky
SGPath ephem_data_path( globals->get_fg_root() );
ephem_data_path.append( "Astro" );
2000-07-08 05:09:24 +00:00
SGEphemeris *ephem = new SGEphemeris( ephem_data_path.c_str() );
ephem->update( globals->get_time_params()->getMjd(),
globals->get_time_params()->getLst(),
0.0 );
globals->set_ephem( ephem );
thesky = new SGSky;
SGPath sky_tex_path( globals->get_fg_root() );
2000-03-06 23:28:43 +00:00
sky_tex_path.append( "Textures" );
sky_tex_path.append( "Sky" );
thesky->texture_path( sky_tex_path.str() );
2000-06-20 02:29:31 +00:00
thesky->build( 550.0, 550.0,
2000-07-08 05:09:24 +00:00
globals->get_ephem()->getNumPlanets(),
globals->get_ephem()->getPlanets(), 60000.0,
globals->get_ephem()->getNumStars(),
globals->get_ephem()->getStars(), 60000.0 );
if ( fgGetBool("/environment/clouds/status") ) {
// thesky->add_cloud_layer( 2000.0, 200.0, 50.0, 40000.0,
// SG_CLOUD_OVERCAST );
thesky->add_cloud_layer( 2600.0, 200.0, 50.0, 40000.0,
2001-04-26 18:15:32 +00:00
SG_CLOUD_MOSTLY_CLOUDY );
// thesky->add_cloud_layer( 3000.0, 200.0, 50.0, 40000.0,
// SG_CLOUD_MOSTLY_SUNNY );
thesky->add_cloud_layer( 6000.0, 20.0, 10.0, 40000.0,
SG_CLOUD_CIRRUS );
}
// Initialize MagVar model
SGMagVar *magvar = new SGMagVar();
globals->set_mag( magvar );
// Terrain branch
terrain = new ssgBranch;
terrain->setName( "Terrain" );
scene->addKid( terrain );
// Lighting
ground = new ssgBranch;
ground->setName( "Ground Lighting" );
lighting->addKid( ground );
airport = new ssgBranch;
airport->setName( "Airport Lighting" );
lighting->addKid( airport );
// ADA
fgLoadDCS();
// ADA
// temporary visible aircraft "own ship"
acmodel_selector = new ssgSelector;
acmodel_pos = new ssgTransform;
ssgEntity *acmodel_obj = NULL;
if (fgGetString("/sim/flight-model") == "ada") {
// ada exteranl aircraft model loading
if( !ship_pos[0]->getKid(0) ) {
// fall back to default
ssgEntity *acmodel_obj = ssgLoad( (char *)"glider.ac" );
if( !acmodel_obj ) {
SG_LOG( SG_GENERAL, SG_ALERT, "FAILED to LOAD an AC model! ..." );
exit(-1);
}
acmodel_pos->addKid( acmodel_obj );
} else {
acmodel_obj = ship_pos[0]->getKid(0);
}
} else {
// default aircraft model loading
// Get the model location, and load textures from the same
// directory. Use an absolute path for the model to avoid
// incompatibilities in different versions of PLIB.
string acmodel_path =
fgGetString("/sim/model/path", "Models/Geometry/glider.ac");
SGPath full_model = globals->get_fg_root();
full_model.append(acmodel_path);
ssgTexturePath( (char *)full_model.dir().c_str() );
acmodel_obj = ssgLoad( (char *)full_model.c_str() );
if( !acmodel_obj ) {
// fall back to default
acmodel_obj = ssgLoad( (char *)"Models/Geometry/glider.ac" );
if( !acmodel_obj ) {
SG_LOG( SG_GENERAL, SG_ALERT, "FAILED to LOAD an AC model! ..." );
exit(-1);
}
}
}
// find moving parts (if this is an MDL model)
flaps_selector = (ssgSelector*)fgFindNode( acmodel_obj, "FLAPS" );
prop_selector = (ssgSelector*)fgFindNode( acmodel_obj, "PROP" );
acmodel_npropsettings = 0;
if (prop_selector != NULL) {
for (ssgEntity* kid = prop_selector->getKid(0); kid != NULL;
kid = prop_selector->getNextKid()) {
int prop_low, prop_high;
if ( sscanf(kid->getName(), "PROP_%d_%d",
&prop_low, &prop_high) == 2 ) {
prop_low = (int)((float)prop_low * (5000.0f / 32767.0f));
prop_high = (int)((float)prop_high * (5000.0f / 32767.0f));
acmodel_proprpms[acmodel_npropsettings][0] = prop_low ;
acmodel_proprpms[acmodel_npropsettings][1] = prop_high;
acmodel_npropsettings++;
2001-03-24 06:03:11 +00:00
SG_LOG( SG_GENERAL, SG_INFO, "PROPELLER SETTING " << prop_low <<
" " << prop_high );
}
}
}
// align the model properly for FGFS
ssgTransform *acmodel_align = new ssgTransform;
acmodel_align->addKid(acmodel_obj);
sgMat4 rot_matrix;
sgMat4 off_matrix;
sgMat4 res_matrix;
float h_rot = fgGetFloat("/sim/model/heading-offset-deg", 0.0);
float p_rot = fgGetFloat("/sim/model/roll-offset-deg", 0.0);
float r_rot = fgGetFloat("/sim/model/pitch-offset-deg", 0.0);
float x_off = fgGetFloat("/sim/model/x-offset-m", 0.0);
float y_off = fgGetFloat("/sim/model/y-offset-m", 0.0);
float z_off = fgGetFloat("/sim/model/z-offset-m", 0.0);
sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
sgMultMat4(res_matrix, off_matrix, rot_matrix);
acmodel_align->setTransform(res_matrix);
acmodel_pos->addKid( acmodel_align );
acmodel_selector->addKid( acmodel_pos );
//ssgFlatten( acmodel_obj );
//ssgStripify( acmodel_selector );
acmodel_selector->clrTraversalMaskBits( SSGTRAV_HOT );
scene->addKid( acmodel_selector );
#ifdef FG_NETWORK_OLK
// Do the network intialization
if ( fgGetBool("/sim/networking/network-olk") ) {
printf("Multipilot mode %s\n", fg_net_init( scene ) );
}
#endif
// build our custom render states
fgBuildRenderStates();
1998-04-24 14:19:29 +00:00
// pass control off to the master GLUT event handler
glutMainLoop();
// we never actually get here ... but to avoid compiler warnings,
// etc.
return 0;
1998-04-21 17:02:27 +00:00
}
// $$$ end - added VS Renganathan, 15 Oct 2K
// - added Venky , 12 Nov 2K
// Main entry point; catch any exceptions that have made it this far.
int main ( int argc, char **argv ) {
#ifdef _MSC_VER
// Christian, we should document what this does
_control87( _EM_INEXACT, _MCW_EM );
#endif
// FIXME: add other, more specific
// exceptions.
try {
mainLoop(argc, argv);
} catch (sg_throwable &t) {
SG_LOG(SG_GENERAL, SG_ALERT,
"Fatal error: " << t.getFormattedMessage()
<< "\n (received from " << t.getOrigin() << ')');
exit(1);
}
return 0;
}
void fgLoadDCS(void) {
ssgEntity *ship_obj = NULL;
char obj_filename[25];
for ( int k = 0; k < 32; k++ ) {
ship_pos[k]=NULL;
}
SGPath tile_path( globals->get_fg_root());
tile_path.append( "Scenery" );
tile_path.append( "Objects.txt" );
sg_gzifstream in( tile_path.str() );
if ( ! in.is_open() ) {
2001-03-24 06:03:11 +00:00
SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: " << tile_path.str() );
} else {
SGPath modelpath( globals->get_fg_root() );
modelpath.append( "Models" );
modelpath.append( "Geometry" );
SGPath texturepath( globals->get_fg_root() );
texturepath.append( "Models" );
texturepath.append( "Textures" );
ssgModelPath( (char *)modelpath.c_str() );
ssgTexturePath( (char *)texturepath.c_str() );
ship_sel = new ssgSelector;
char c;
while ( ! in.eof() ) {
in >> ::skipws;
if ( in.get( c ) && c == '#' ) {
in >> skipeol;
} else {
in.putback(c);
in >> obj_filename >> obj_lat[objc] >> obj_lon[objc] >> obj_alt[objc];
/* cout << endl << obj_filename << " " << obj_lat[objc] << " " << obj_lon[objc] << " " << obj_alt[objc] << endl;
int chj=getchar();*/
obj_lon[objc] *=SGD_DEGREES_TO_RADIANS;
obj_lat[objc] *=SGD_DEGREES_TO_RADIANS;
ship_pos[objc] = new ssgTransform;
// type "repeat" in objects.txt to load one more
// instance of the last object.
if ( strcmp(obj_filename,"repeat") != 0) {
ship_obj = ssgLoad( obj_filename );
}
if ( ship_obj != NULL ) {
ship_obj->setName(obj_filename);
if (objc == 0)
ship_obj->clrTraversalMaskBits( SSGTRAV_HOT );
else
ship_obj->setTraversalMaskBits( SSGTRAV_HOT );
ship_pos[objc]->addKid( ship_obj ); // add object to transform node
ship_sel->addKid( ship_pos[objc] ); // add transform node to selector
SG_LOG( SG_TERRAIN, SG_ALERT, "Loaded file: "
<< obj_filename );
} else {
SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: "
<< obj_filename );
}
// temporary hack for deck lights - ultimately should move to PLib (when??)
//const char *extn = file_extension ( obj_filename ) ;
if ( objc == 1 ){
ssgVertexArray *lights = new ssgVertexArray( 100 );
ssgVertexArray *lightpoints = new ssgVertexArray( 100 );
ssgVertexArray *lightnormals = new ssgVertexArray( 100 );
ssgVertexArray *lightdir = new ssgVertexArray( 100 );
int ltype[500], light_type;
static int ltcount = 0;
string token;
sgVec3 rway_dir,rway_normal,lightpt;
Point3D node;
modelpath.append(obj_filename);
sg_gzifstream in1( modelpath.str() );
if ( ! in1.is_open() ) {
SG_LOG( SG_TERRAIN, SG_ALERT, "Cannot open file: " << modelpath.str() );
} else {
while ( ! in1.eof() ) {
in1 >> ::skipws;
if ( in1.get( c ) && c == '#' ) {
in1 >> skipeol;
} else {
in1.putback(c);
in1 >> token;
//cout << token << endl;
if ( token == "runway" ) {
in1 >> node;
sgSetVec3 (rway_dir, node[0], node[1], node[2] );
} else if ( token == "edgelight" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 1;
} else if ( token == "taxi" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 2;
} else if ( token == "vasi" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 3;
} else if ( token == "threshold" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 4;
} else if ( token == "rabbit" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 5;
} else if ( token == "ols" ) {
in1 >> node;
sgSetVec3 (rway_ols, node[0], node[1], node[2] );
light_type = 6;
} else if ( token == "red" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 7;
} else if ( token == "green" ) {
in1 >> node;
sgSetVec3 (rway_normal, node[0], node[1], node[2] );
light_type = 8;
} else if ( token == "lp" ) {
in1 >> node;
sgSetVec3 (lightpt, node[0], node[1], node[2] );
lightpoints->add( lightpt );
lightnormals->add( rway_normal );
lightdir->add( rway_dir );
ltype[ltcount]= light_type;
ltcount++;
}
if (in1.eof()) break;
}
} //while
if ( lightpoints->getNum() ) {
ssgBranch *lightpoints_branch;
long int dummy = -999;
dummy_tile = new FGTileEntry((SGBucket)dummy);
dummy_tile->lightmaps_sequence = new ssgSelector;
dummy_tile->ols_transform = new ssgTransform;
// call function to generate the runway lights
lightpoints_branch =
dummy_tile->gen_runway_lights( lightpoints, lightnormals,
lightdir, ltype);
lightpoints_brightness->addKid(lightpoints_branch);
lightpoints_transform->addKid(lightpoints_brightness);
//dummy_tile->lightmaps_sequence->setTraversalMaskBits( SSGTRAV_HOT );
lightpoints_transform->addKid( dummy_tile->lightmaps_sequence );
lightpoints_transform->ref();
ground->addKid( lightpoints_transform );
}
} //if in1
} //if objc
// end hack for deck lights
objc++;
if (in.eof()) break;
}
} // while
SG_LOG ( SG_TERRAIN, SG_ALERT, "Finished object processing." );
terrain->addKid( ship_sel ); //add selector node to root node
}
return;
}
void fgUpdateDCS (void) {
// double eye_lat,eye_lon,eye_alt;
// static double obj_head;
double sl_radius,obj_latgc;
// float nresultmat[4][4];
// sgMat4 Trans,rothead,rotlon,rot180,rotlat,resultmat1,resultmat2,resultmat3;
double bz[3];
// Instantaneous Geodetic Lat/Lon/Alt of moving object
FGADA *fdm = (FGADA *)current_aircraft.fdm_state;
// Deck should be the first object in objects.txt in case of fdm=ada
if (fgGetString("/sim/flight-model") == "ada") {
if ((fdm->get_iaux(1))==1)
{
obj_lat[1] = fdm->get_daux(1)*SGD_DEGREES_TO_RADIANS;
obj_lon[1] = fdm->get_daux(2)*SGD_DEGREES_TO_RADIANS;
obj_alt[1] = fdm->get_daux(3);
obj_pitch[1] = fdm->get_faux(1);
obj_roll[1] = fdm->get_faux(2);
}
}
for ( int m = 0; m < objc; m++ ) {
2001-03-24 04:48:44 +00:00
//cout << endl << obj_lat[m]*SGD_RADIANS_TO_DEGREES << " " << obj_lon[m]*SGD_RADIANS_TO_DEGREES << " " << obj_alt[m] << " " << objc << endl;
//int v=getchar();
//Geodetic to Geocentric angles for rotation
sgGeodToGeoc(obj_lat[m],obj_alt[m],&sl_radius,&obj_latgc);
//moving object gbs-posn in cartesian coords
Point3D obj_posn = Point3D( obj_lon[m],obj_lat[m],obj_alt[m]);
Point3D obj_pos = sgGeodToCart( obj_posn );
// Translate moving object w.r.t eye
Point3D Objtrans = obj_pos-scenery.center;
bz[0]=Objtrans.x();
bz[1]=Objtrans.y();
bz[2]=Objtrans.z();
// rotate dynamic objects for lat,lon & alt and other motion about its axes
sgMat4 sgTRANS;
sgMakeTransMat4( sgTRANS, bz[0],bz[1],bz[2]);
sgVec3 ship_fwd,ship_rt,ship_up;
sgSetVec3( ship_fwd, 1.0, 0.0, 0.0);//east,roll
sgSetVec3( ship_rt, 0.0, 1.0, 0.0);//up,pitch
sgSetVec3( ship_up, 0.0, 0.0, 1.0); //north,yaw
sgMat4 sgROT_lon, sgROT_lat, sgROT_hdg, sgROT_pitch, sgROT_roll;
2001-03-24 04:48:44 +00:00
sgMakeRotMat4( sgROT_lon, obj_lon[m]*SGD_RADIANS_TO_DEGREES, ship_up );
sgMakeRotMat4( sgROT_lat, 90-obj_latgc*SGD_RADIANS_TO_DEGREES, ship_rt );
sgMakeRotMat4( sgROT_hdg, 180.0, ship_up );
sgMakeRotMat4( sgROT_pitch, obj_pitch[m], ship_rt );
sgMakeRotMat4( sgROT_roll, obj_roll[m], ship_fwd );
sgMat4 sgTUX;
sgCopyMat4( sgTUX, sgROT_hdg );
sgPostMultMat4( sgTUX, sgROT_pitch );
sgPostMultMat4( sgTUX, sgROT_roll );
sgPostMultMat4( sgTUX, sgROT_lat );
sgPostMultMat4( sgTUX, sgROT_lon );
sgPostMultMat4( sgTUX, sgTRANS );
sgCoord shippos;
sgSetCoord(&shippos, sgTUX );
ship_pos[m]->setTransform( &shippos );
// temporary hack for deck lights - ultimately should move to PLib (when ??)
if (m == 1) {
if (lightpoints_transform) {
lightpoints_transform->setTransform( &shippos );
float sun_angle = cur_light_params.sun_angle * SGD_RADIANS_TO_DEGREES;
if ( sun_angle > 89 ) {
lightpoints_brightness->select(0x01);
} else {
lightpoints_brightness->select(0x00);
}
}
float elev;
sgVec3 rp,to;
float *vp;
float alt;
float ref_elev;
sgXformPnt3( rp, rway_ols, sgTUX );
vp = globals->get_current_view()->get_view_pos();
to[0] = rp[0]-vp[0];
to[1] = rp[1]-vp[1];
to[2] = rp[2]-vp[2];
float dist = sgLengthVec3( to );
alt = (current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER)-rway_ols[2];
elev = asin(alt/dist)*SGD_RADIANS_TO_DEGREES;
ref_elev = elev - 3.75; // +ve above, -ve below
unsigned int sel;
sel = 0xFF;
// DO NOT DELETE THIS CODE - This is to compare a discrete FLOLS (without LOD) with analog FLOLS
// if (ref_elev > 0.51) sel = 0x21;
// if ((ref_elev <= 0.51) & (ref_elev > 0.17)) sel = 0x22;
// if ((ref_elev <= 0.17) & (ref_elev >= -0.17)) sel = 0x24;
// if ((ref_elev < -0.17) & (ref_elev >= -0.51)) sel = 0x28;
// if (ref_elev < -0.51) sel = 0x30;
// DO NOT DELETE THIS CODE - This is to compare a discrete FLOLS (without LOD) with analog FLOLS
dummy_tile->lightmaps_sequence->select(sel);
sgVec3 up;
sgCopyVec3 (up, ship_up);
if (dist > 750)
sgScaleVec3 (up, 4.0*ref_elev*dist/750.0);
else
sgScaleVec3 (up, 4.0*ref_elev);
dummy_tile->ols_transform->setTransform(up);
//cout << "ref_elev " << ref_elev << endl;
}
// end hack for deck lights
}
if ( ship_sel != NULL ) {
ship_sel->select(0xFFFFFFFE); // first object is ownship, added to acmodel
}
}
// $$$ end - added VS Renganathan, 15 Oct 2K
// added Venky , 12 Nov 2K