diff --git a/docs-mini/README.multiscreen b/docs-mini/README.multiscreen index 9954f13f9..042bbac84 100644 --- a/docs-mini/README.multiscreen +++ b/docs-mini/README.multiscreen @@ -133,6 +133,30 @@ window, camera, or gui tags. This specifies an orthographic view. The parameters are the sames as the frustum node's. + texture + This tag indicates that the camera renders to a texture instead of the + framebuffer. For now the following tags are supported, but obviously + different texture formats should be specified too. + name - string + The name of the texture. This can be referred to by other cameras. + width, height - double + The dimensions of the texture + + panoramic-distortion + This tag cause the camera to create distortion geometry that + corrects for projection onto a spherical screen. It is equivalent to + the --panoramic-sd option to osgviewer. + + texture - string + The name of a texture, created by another camera, that will be + rendered on the distortion correction geometry. + + radius - double + Radius of string + + collar - double + size of screen collar. + gui This is a special camera node that displays the 2D GUI. @@ -313,3 +337,61 @@ accounted for. + +This example renders the scene for projection onto a spherical screen. + + + + + + + + main + + 0 + 0 + + 1024 + 768 + + + 0 + + + 0.133 + -0.133 + -.1668 + .1668 + 0.4 + 120000.0 + + + mainview + 1024 + 768 + + + + main + + 768 + 0 + 0 + 1024 + -1.0 + 1.0 + + + mainview + + + + + main + + + + + + + diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index a0faf6eca..16b15fe1d 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -152,11 +152,11 @@ bool FGAIBallistic::init(bool search_in_AI_path) { props->setStringValue("contents/path", _contents_path.c_str()); } - if(_parent != ""){ - setParentNode(); - } + //if(_parent != ""){ + // setParentNode(); + //} - setParentNodes(_selected_ac); + //setParentNodes(_selected_ac); //props->setStringValue("vector/path", _vector_path.c_str()); @@ -168,7 +168,11 @@ bool FGAIBallistic::init(bool search_in_AI_path) { Transform(); - //cout << _name << " speed init: " << speed << endl; + if(_parent != ""){ + setParentNode(); + } + + setParentNodes(_selected_ac); return true; } diff --git a/src/AIModel/AIWingman.cxx b/src/AIModel/AIWingman.cxx index 7233abd2b..cef9ad737 100644 --- a/src/AIModel/AIWingman.cxx +++ b/src/AIModel/AIWingman.cxx @@ -215,13 +215,14 @@ bool FGAIWingman::init(bool search_in_AI_path) { roll = _rotation; _ht_agl_ft = 1e10; - props->setStringValue("submodels/path", _path.c_str()); - if(_parent != ""){ setParentNode(); } setParentNodes(_selected_ac); + + props->setStringValue("submodels/path", _path.c_str()); + user_WoW_node = fgGetNode("gear/gear[1]/wow", true); return true; } @@ -277,7 +278,7 @@ double FGAIWingman::calcAngle(double range, SGGeod pos1, SGGeod pos2){ void FGAIWingman::formateToAC(double dt){ - double p_hdg, p_pch, p_rll, p_agl, p_ht = 0; + double p_hdg, p_pch, p_rll, p_agl, p_ht, p_wow = 0; setTgtOffsets(dt, 25); @@ -312,8 +313,9 @@ void FGAIWingman::formateToAC(double dt){ double h_feet = 3 * factor; p_agl = manager->get_user_agl(); + p_wow = user_WoW_node->getDoubleValue(); - if(p_agl <= 10) { + if(p_agl <= 10 || p_wow == 1) { _height = p_ht; //cout << "ht case1 " ; } else if (p_agl > 10 && p_agl <= 150 ) { @@ -332,7 +334,8 @@ void FGAIWingman::formateToAC(double dt){ pos.setLongitudeDeg(_offsetpos.getLongitudeDeg()); // these calculations are unreliable at slow speeds - if(speed >= 10) { + // and we don't want random movement on the ground + if(speed >= 10 && p_wow != 1) { setHdg(p_hdg + h_angle, dt, 0.9); setPch(p_pch + p_angle + _pitch_offset, dt, 0.9); diff --git a/src/AIModel/AIWingman.hxx b/src/AIModel/AIWingman.hxx index 038df5d08..42c51094c 100644 --- a/src/AIModel/AIWingman.hxx +++ b/src/AIModel/AIWingman.hxx @@ -67,7 +67,7 @@ private: double _coeff_bnk; //dimensionless coefficient double _coeff_spd; //dimensionless coefficient - + SGPropertyNode_ptr user_WoW_node; inline void setFormate(bool f); inline void setTgtHdg(double hdg); diff --git a/src/Instrumentation/heading_indicator_dg.cxx b/src/Instrumentation/heading_indicator_dg.cxx index d9923c2e5..9bcd19b67 100644 --- a/src/Instrumentation/heading_indicator_dg.cxx +++ b/src/Instrumentation/heading_indicator_dg.cxx @@ -7,6 +7,7 @@ // This file is in the Public Domain and comes with no warranty. #include +#include #include #include #include @@ -54,15 +55,26 @@ HeadingIndicatorDG::init () branch = "/instrumentation/" + name; _heading_in_node = fgGetNode("/orientation/heading-deg", true); + _yaw_rate_node = fgGetNode("/orientation/yaw-rate-degps", true); + _g_node = fgGetNode("/accelerations/pilot-g", true); + + SGPropertyNode *node = fgGetNode(branch.c_str(), num, true ); _offset_node = node->getChild("offset-deg", 0, true); _serviceable_node = node->getChild("serviceable", 0, true); - _error_node = node->getChild("heading-bug-error-deg", 0, true); + _heading_bug_error_node = node->getChild("heading-bug-error-deg", 0, true); + _error_node = node->getChild("error-deg", 0, true); _nav1_error_node = node->getChild("nav1-course-error-deg", 0, true); _heading_out_node = node->getChild("indicated-heading-deg", 0, true); - _last_heading_deg = (_heading_in_node->getDoubleValue() + - _offset_node->getDoubleValue()); + _align_node = node->getChild("align-deg", 0, true); + _electrical_node = fgGetNode("/systems/electrical/outputs/DG", true); + + _align_node->setDoubleValue(0); + _error_node->setDoubleValue(0); + + _last_heading_deg = (_heading_in_node->getDoubleValue() + + _offset_node->getDoubleValue() + _align_node->getDoubleValue()); } void @@ -100,11 +112,30 @@ HeadingIndicatorDG::update (double dt) _gyro.update(dt); double spin = _gyro.get_spin_norm(); - // No time-based precession for a flux gate compass - // No magvar - double offset = 0; + // Next, calculate time-based precession + double offset = _offset_node->getDoubleValue(); + offset -= dt * (0.25 / 60.0); // 360deg/day + SG_NORMALIZE_RANGE(offset, -360.0, 360.0); + _offset_node->setDoubleValue(offset); - // TODO: movement-induced error + // No magvar - set the alignment manually + double align = _align_node->getDoubleValue(); + + // Movement-induced error + double yaw_rate = _yaw_rate_node->getDoubleValue(); + double error = _error_node->getDoubleValue(); + double g = _g_node->getDoubleValue(); + int sign = 0; + + if ( fabs ( yaw_rate ) > 5 ) { + error += 0.033 * -yaw_rate * dt ; + } + + if ( g > 1.5 || g < -0.5){ + error += 0.033 * g * dt; + } + + _error_node->setDoubleValue(error); // Next, calculate the indicated heading, // introducing errors. @@ -122,11 +153,8 @@ HeadingIndicatorDG::update (double dt) heading = fgGetLowPass(_last_heading_deg, heading, dt * factor); _last_heading_deg = heading; - heading += offset; - while (heading < 0) - heading += 360; - while (heading > 360) - heading -= 360; + heading += offset + align + error; + SG_NORMALIZE_RANGE(heading, 0.0, 360.0); _heading_out_node->setDoubleValue(heading); @@ -138,7 +166,7 @@ HeadingIndicatorDG::update (double dt) double diff = bnode->getDoubleValue() - heading; if ( diff < -180.0 ) { diff += 360.0; } if ( diff > 180.0 ) { diff -= 360.0; } - _error_node->setDoubleValue( diff ); + _heading_bug_error_node->setDoubleValue( diff ); } // calculate the difference between the indicated heading // and the selected nav1 radial for use with an autopilot @@ -152,4 +180,4 @@ HeadingIndicatorDG::update (double dt) } } -// end of heading_indicator_fg.cxx +// end of heading_indicator_dg.cxx diff --git a/src/Instrumentation/heading_indicator_dg.hxx b/src/Instrumentation/heading_indicator_dg.hxx index 89c22f3b9..d016ca45b 100644 --- a/src/Instrumentation/heading_indicator_dg.hxx +++ b/src/Instrumentation/heading_indicator_dg.hxx @@ -1,64 +1,69 @@ -// heading_indicator.hxx - a vacuum-powered heading indicator. -// Written by David Megginson, started 2002. -// -// This file is in the Public Domain and comes with no warranty. - - -#ifndef __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX -#define __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX 1 - - -#include -#include - -#include "gyro.hxx" - - -/** - * Model an electrically-powered heading indicator. - * - * Input properties: - * - * /instrumentation/"name"/serviceable - * /instrumentation/"name"/spin - * /instrumentation/"name"/offset-deg - * /orientation/heading-deg - * /systems/electrical/outputs/DG - * - * Output properties: - * - * /instrumentation/"name"/indicated-heading-deg - */ -class HeadingIndicatorDG : public SGSubsystem -{ - -public: - - HeadingIndicatorDG ( SGPropertyNode *node ); - HeadingIndicatorDG (); - virtual ~HeadingIndicatorDG (); - - virtual void init (); - virtual void bind (); - virtual void unbind (); - virtual void update (double dt); - -private: - - Gyro _gyro; - double _last_heading_deg; - - string name; - int num; - //string vacuum_system; - - SGPropertyNode_ptr _offset_node; - SGPropertyNode_ptr _heading_in_node; - SGPropertyNode_ptr _serviceable_node; - SGPropertyNode_ptr _heading_out_node; - SGPropertyNode_ptr _electrical_node; - SGPropertyNode_ptr _error_node; - SGPropertyNode_ptr _nav1_error_node; -}; - -#endif // __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX +// heading_indicator.hxx - a vacuum-powered heading indicator. +// Written by David Megginson, started 2002. +// +// This file is in the Public Domain and comes with no warranty. + + +#ifndef __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX +#define __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX 1 + + +#include +#include +#include + +#include "gyro.hxx" + + +/** + * Model an electrically-powered heading indicator. + * + * Input properties: + * + * /instrumentation/"name"/serviceable + * /instrumentation/"name"/spin + * /instrumentation/"name"/offset-deg + * /orientation/heading-deg + * /systems/electrical/outputs/DG + * + * Output properties: + * + * /instrumentation/"name"/indicated-heading-deg + */ +class HeadingIndicatorDG : public SGSubsystem +{ + +public: + + HeadingIndicatorDG ( SGPropertyNode *node ); + HeadingIndicatorDG (); + virtual ~HeadingIndicatorDG (); + + virtual void init (); + virtual void bind (); + virtual void unbind (); + virtual void update (double dt); + +private: + + Gyro _gyro; + double _last_heading_deg; + + string name; + int num; + //string vacuum_system; + + SGPropertyNode_ptr _offset_node; + SGPropertyNode_ptr _heading_in_node; + SGPropertyNode_ptr _serviceable_node; + SGPropertyNode_ptr _heading_out_node; + SGPropertyNode_ptr _electrical_node; + SGPropertyNode_ptr _error_node; + SGPropertyNode_ptr _nav1_error_node; + SGPropertyNode_ptr _align_node; + SGPropertyNode_ptr _yaw_rate_node; + SGPropertyNode_ptr _heading_bug_error_node; + SGPropertyNode_ptr _g_node; +}; + +#endif // __INSTRUMENTS_HEADING_INDICATOR_ELEC_HXX diff --git a/src/Instrumentation/mrg.cxx b/src/Instrumentation/mrg.cxx index 539231da4..365447b45 100644 --- a/src/Instrumentation/mrg.cxx +++ b/src/Instrumentation/mrg.cxx @@ -20,10 +20,11 @@ #include "mrg.hxx" +const double MasterReferenceGyro::gravity = -32.1740485564; MasterReferenceGyro::MasterReferenceGyro ( SGPropertyNode *node ) : - _name(node->getStringValue("name", "master-reference-gyro")), - _num(node->getIntValue("number", 0)) +_name(node->getStringValue("name", "master-reference-gyro")), +_num(node->getIntValue("number", 0)) { } @@ -34,237 +35,252 @@ MasterReferenceGyro::~MasterReferenceGyro () void MasterReferenceGyro::init () { - _last_hdg = 0; - _last_roll = 0; - _last_pitch = 0; - _indicated_hdg = 0; - _indicated_roll = 0; - _indicated_pitch = 0; - _indicated_hdg_rate = 0; - _indicated_roll_rate = 0; - _indicated_pitch_rate = 0; - _erect_time = 0; - - string branch; - branch = "/instrumentation/" + _name; + _last_hdg = 0; + _last_roll = 0; + _last_pitch = 0; + _indicated_hdg = 0; + _indicated_roll = 0; + _indicated_pitch = 0; + _indicated_hdg_rate = 0; + _indicated_roll_rate = 0; + _indicated_pitch_rate = 0; + _erect_time = 180; + _last_g = 1; + _g_error = 10; - _pitch_in_node = fgGetNode("/orientation/pitch-deg", true); - _roll_in_node = fgGetNode("/orientation/roll-deg", true); - _hdg_in_node = fgGetNode("/orientation/heading-deg", true); - _hdg_mag_in_node = fgGetNode("/orientation/heading-magnetic-deg", true); - _pitch_rate_node = fgGetNode("/orientation/pitch-rate-degps", true); - _roll_rate_node = fgGetNode("/orientation/roll-rate-degps", true); - _yaw_rate_node = fgGetNode("/orientation/yaw-rate-degps", true); - _g_in_node = fgGetNode("/accelerations/pilot-g", true); - _electrical_node = fgGetNode("/systems/electrical/outputs/MRG", true); - _hdg_mag_in_node = fgGetNode("/orientation/heading-magnetic-deg", true); - - SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true ); - _off_node = node->getChild("off-flag", 0, true); - _pitch_out_node = node->getChild("indicated-pitch-deg", 0, true); - _roll_out_node = node->getChild("indicated-roll-deg", 0, true); - _hdg_out_node = node->getChild("indicated-hdg-deg", 0, true); - _hdg_mag_out_node = node->getChild("indicated-mag-hdg-deg", 0, true); - _pitch_rate_out_node = node->getChild("indicated-pitch-rate-degps", 0, true); - _roll_rate_out_node = node->getChild("indicated-roll-rate-degps", 0, true); - _hdg_rate_out_node = node->getChild("indicated-hdg-rate-degps", 0, true); - _responsiveness_node = node->getChild("responsiveness", 0, true); - _error_out_node = node->getChild("heading-bug-error-deg", 0, true); - _hdg_input_source_node = node->getChild("heading-source", 0, true); - _fast_erect_node = node->getChild("fast-erect", 0, true); + string branch; + branch = "/instrumentation/" + _name; - _electrical_node->setDoubleValue(0); - _responsiveness_node->setDoubleValue(0.75); - _off_node->setBoolValue(false); - _hdg_input_source_node->setBoolValue(false); - _fast_erect_node->setBoolValue(false); + _pitch_in_node = fgGetNode("/orientation/pitch-deg", true); + _roll_in_node = fgGetNode("/orientation/roll-deg", true); + _hdg_in_node = fgGetNode("/orientation/heading-deg", true); + _hdg_mag_in_node = fgGetNode("/orientation/heading-magnetic-deg", true); + _pitch_rate_node = fgGetNode("/orientation/pitch-rate-degps", true); + _roll_rate_node = fgGetNode("/orientation/roll-rate-degps", true); + _yaw_rate_node = fgGetNode("/orientation/yaw-rate-degps", true); + //_g_in_node = fgGetNode("/accelerations/pilot/z-accel-fps_sec", true); + _g_in_node = fgGetNode("/accelerations/pilot-g", true); + _electrical_node = fgGetNode("/systems/electrical/outputs/MRG", true); + _hdg_mag_in_node = fgGetNode("/orientation/heading-magnetic-deg", true); + + SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true ); + _off_node = node->getChild("off-flag", 0, true); + _pitch_out_node = node->getChild("indicated-pitch-deg", 0, true); + _roll_out_node = node->getChild("indicated-roll-deg", 0, true); + _hdg_out_node = node->getChild("indicated-hdg-deg", 0, true); + _hdg_mag_out_node = node->getChild("indicated-mag-hdg-deg", 0, true); + _pitch_rate_out_node = node->getChild("indicated-pitch-rate-degps", 0, true); + _roll_rate_out_node = node->getChild("indicated-roll-rate-degps", 0, true); + _hdg_rate_out_node = node->getChild("indicated-hdg-rate-degps", 0, true); + _responsiveness_node = node->getChild("responsiveness", 0, true); + _error_out_node = node->getChild("heading-bug-error-deg", 0, true); + _hdg_input_source_node = node->getChild("heading-source", 0, true); + _fast_erect_node = node->getChild("fast-erect", 0, true); + + _electrical_node->setDoubleValue(0); + _responsiveness_node->setDoubleValue(0.75); + _off_node->setBoolValue(false); + _hdg_input_source_node->setBoolValue(false); + _fast_erect_node->setBoolValue(false); + _g_in_node->setDoubleValue(1); } void MasterReferenceGyro::bind () { - std::ostringstream temp; - string branch; - temp << _num; - branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; + std::ostringstream temp; + string branch; + temp << _num; + branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; - fgTie((branch + "/serviceable").c_str(), - &_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable); - fgTie((branch + "/spin").c_str(), - &_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm); + fgTie((branch + "/serviceable").c_str(), + &_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable); + fgTie((branch + "/spin").c_str(), + &_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm); } void MasterReferenceGyro::unbind () { - std::ostringstream temp; - string branch; - temp << _num; - branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; + std::ostringstream temp; + string branch; + temp << _num; + branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; - fgUntie((branch + "/serviceable").c_str()); - fgUntie((branch + "/spin").c_str()); + fgUntie((branch + "/serviceable").c_str()); + fgUntie((branch + "/spin").c_str()); } void MasterReferenceGyro::update (double dt) { - double indicated_roll = 0; - double indicated_pitch = 0; - double indicated_hdg = 0; - double indicated_roll_rate = 0; - double indicated_pitch_rate = 0; - double indicated_hdg_rate = 0; - - // Get the spin from the gyro - _gyro.set_power_norm( _electrical_node->getDoubleValue()/24 ); - _gyro.update(dt); - double spin = _gyro.get_spin_norm(); - - // set the "off-flag" - if ( _electrical_node->getDoubleValue() > 0 && spin >= 0.25) { - _off_node->setBoolValue(false); - } else { - _off_node->setBoolValue(true); + //sanity check + if (!fgGetBool("/sim/fdm-initialized", false)) { return; - } + } - // Get the input values - double hdg = _hdg_mag_in_node->getDoubleValue(); + double indicated_roll = 0; + double indicated_pitch = 0; + double indicated_hdg = 0; + double indicated_roll_rate = 0; + double indicated_pitch_rate = 0; + double indicated_hdg_rate = 0; + double hdg = 0; + double erect_time_factor = 1; - if(_hdg_input_source_node->getBoolValue()) - hdg = _hdg_in_node->getDoubleValue(); + const double erect_time = 180; + const double max_g_error = 10.0; - double roll = _roll_in_node->getDoubleValue(); - double pitch = _pitch_in_node->getDoubleValue(); - - double roll_rate = _yaw_rate_node->getDoubleValue(); - double pitch_rate = _yaw_rate_node->getDoubleValue(); - double yaw_rate = _yaw_rate_node->getDoubleValue(); - double g = _g_in_node->getDoubleValue(); + //Get the spin from the gyro + _gyro.set_power_norm( _electrical_node->getDoubleValue()/24 ); + _gyro.update(dt); + double spin = _gyro.get_spin_norm(); - //modulate the input by the spin rate - double responsiveness = spin * spin * spin * spin * spin * spin; - roll = fgGetLowPass( _last_roll, roll, responsiveness ); - pitch = fgGetLowPass( _last_pitch , pitch, responsiveness ); + // set the "off-flag" + if ( _electrical_node->getDoubleValue() > 0 && spin >= 0.25) { + _off_node->setBoolValue(false); + } else { + _off_node->setBoolValue(true); + return; + } - if ((hdg - _last_hdg) > 180) - _last_hdg += 360; - if ((hdg - _last_hdg) < -180) - _last_hdg -= 360; + // Get the input values + if(_hdg_input_source_node->getBoolValue()){ + hdg = _hdg_in_node->getDoubleValue(); + } else { + hdg = _hdg_mag_in_node->getDoubleValue(); + } - hdg = fgGetLowPass( _last_hdg , hdg, responsiveness ); + double roll = _roll_in_node->getDoubleValue(); + double pitch = _pitch_in_node->getDoubleValue(); + double g = _g_in_node->getDoubleValue()/* / gravity*/; - //but we need to filter the hdg and yaw_rate as well - yuk! - responsiveness = 0.1 / (spin * spin * spin * spin * spin * spin); - yaw_rate = fgGetLowPass( _last_yaw_rate , yaw_rate, responsiveness ); - g = fgGetLowPass( _last_g , g, 0.015 ); + double roll_rate = _yaw_rate_node->getDoubleValue(); + double pitch_rate = _pitch_rate_node->getDoubleValue(); + double yaw_rate = _yaw_rate_node->getDoubleValue(); + + //modulate the input by the spin rate + double responsiveness = spin * spin * spin * spin * spin * spin; + roll = fgGetLowPass( _last_roll, roll, responsiveness ); + pitch = fgGetLowPass( _last_pitch , pitch, responsiveness ); + + if ((hdg - _last_hdg) > 180) + _last_hdg += 360; + if ((hdg - _last_hdg) < -180) + _last_hdg -= 360; + + hdg = fgGetLowPass( _last_hdg , hdg, responsiveness ); + + //but we need to filter the hdg and yaw_rate as well - yuk! + responsiveness = 0.1 / (spin * spin * spin * spin * spin * spin); + yaw_rate = fgGetLowPass( _last_yaw_rate , yaw_rate, responsiveness ); + g = fgGetLowPass( _last_g , g, 1.5); - // store the new values - _last_roll = roll; - _last_pitch = pitch; - _last_hdg = hdg; - _last_roll_rate = roll_rate; - _last_pitch_rate = pitch_rate; - _last_yaw_rate = yaw_rate; - _last_g = g; + // store the new values + _last_roll = roll; + _last_pitch = pitch; + _last_hdg = hdg; + _last_roll_rate = roll_rate; + _last_pitch_rate = pitch_rate; + _last_yaw_rate = yaw_rate; + _last_g = g; - if (_erect_time > 0){ + //the gyro only erects inside limits + if ( fabs ( yaw_rate ) <= 5 + && g <= 1.5 && g >= -0.5){ - if ( !_fast_erect_node->getBoolValue() ) - _erect_time -= dt; - else - _erect_time -= 2 * dt; + if ( !_fast_erect_node->getBoolValue() ){ + erect_time_factor = 1; + } else { + erect_time_factor = 2; + } + + _g_error -= (max_g_error/(erect_time * 0.33)) * dt * erect_time_factor; + } else { + _g_error += (max_g_error /(erect_time * 0.33)) * dt * 2; + + //SG_LOG(SG_GENERAL, SG_ALERT,_num << + // " g input " << _g_in_node->getDoubleValue() * gravity + // <<" _erect_time " << _erect_time + // << " yaw " << yaw_rate + // << " pitch " << _pitch_rate_node->getDoubleValue() + // << " roll " << _roll_rate_node->getDoubleValue()); } - //SG_LOG(SG_GENERAL, SG_ALERT, - // "g input " << g <<" _erect_time " << _erect_time << " spin " << spin); + //cout << "_g_error "<< _g_error << endl; + _g_error = SGMiscd::clip(_g_error, 0, 10); +// cout << "_g_error clip "<< _g_error << endl; + indicated_roll = _last_roll + _g_error; + indicated_pitch = _last_pitch + _g_error; + indicated_hdg = _last_hdg + _g_error; + indicated_roll_rate = _last_roll_rate; + indicated_pitch_rate = _last_pitch_rate; + indicated_hdg_rate = _last_yaw_rate; + // calculate the difference between the indicated heading + // and the selected heading for use with an autopilot + static SGPropertyNode *bnode + = fgGetNode( "/autopilot/settings/heading-bug-deg", false ); - //the gyro only erects inside limits - if ( fabs ( yaw_rate ) <= 5 - && ( g <= 1.5 || g >= -0.5) - && _erect_time <=0 ) { - indicated_roll = _last_roll; - indicated_pitch = _last_pitch; - indicated_hdg = _last_hdg; - indicated_roll_rate = _last_roll_rate; - indicated_pitch_rate = _last_pitch_rate; - indicated_hdg_rate = _last_yaw_rate; - } else { - indicated_roll_rate = 0; - indicated_pitch_rate = 0; - indicated_hdg_rate = 0; - - if (_erect_time <= 0 ) - _erect_time = 34; + if ( bnode ) { + double diff = bnode->getDoubleValue() - indicated_hdg; + if ( diff < -180.0 ) { diff += 360.0; } + if ( diff > 180.0 ) { diff -= 360.0; } + _error_out_node->setDoubleValue( diff ); + //SG_LOG(SG_GENERAL, SG_ALERT, + //"autopilot input " << bnode->getDoubleValue() + //<< " output " << _error_out_node->getDoubleValue()<<); + } - } + //smooth the output + double factor = _responsiveness_node->getDoubleValue() * dt; - // calculate the difference between the indicated heading - // and the selected heading for use with an autopilot - static SGPropertyNode *bnode - = fgGetNode( "/autopilot/settings/heading-bug-deg", false ); + indicated_roll = fgGetLowPass( _indicated_roll, indicated_roll, factor ); + indicated_pitch = fgGetLowPass( _indicated_pitch , indicated_pitch, factor ); + //indicated_hdg = fgGetLowPass( _indicated_hdg , indicated_hdg, factor ); - if ( bnode ) { - double diff = bnode->getDoubleValue() - indicated_hdg; - if ( diff < -180.0 ) { diff += 360.0; } - if ( diff > 180.0 ) { diff -= 360.0; } - _error_out_node->setDoubleValue( diff ); - //SG_LOG(SG_GENERAL, SG_ALERT, - //"autopilot input " << bnode->getDoubleValue() - //<< " output " << _error_out_node->getDoubleValue()<<); - } - - //smooth the output - double factor = _responsiveness_node->getDoubleValue() * dt; + indicated_roll_rate = fgGetLowPass( _indicated_roll_rate, indicated_roll_rate, factor ); + indicated_pitch_rate = fgGetLowPass( _indicated_pitch_rate , indicated_pitch_rate, factor ); + indicated_hdg_rate = fgGetLowPass( _indicated_hdg_rate , indicated_hdg_rate, factor ); - indicated_roll = fgGetLowPass( _indicated_roll, indicated_roll, factor ); - indicated_pitch = fgGetLowPass( _indicated_pitch , indicated_pitch, factor ); - //indicated_hdg = fgGetLowPass( _indicated_hdg , indicated_hdg, factor ); + // store the new values + _indicated_roll = indicated_roll; + _indicated_pitch = indicated_pitch; + _indicated_hdg = indicated_hdg; - indicated_roll_rate = fgGetLowPass( _indicated_roll_rate, indicated_roll_rate, factor ); - indicated_pitch_rate = fgGetLowPass( _indicated_pitch_rate , indicated_pitch_rate, factor ); - indicated_hdg_rate = fgGetLowPass( _indicated_hdg_rate , indicated_hdg_rate, factor ); + _indicated_roll_rate = indicated_roll_rate; + _indicated_pitch_rate = indicated_pitch_rate; + _indicated_hdg_rate = indicated_hdg_rate; - // store the new values - _indicated_roll = indicated_roll; - _indicated_pitch = indicated_pitch; - _indicated_hdg = indicated_hdg; + // add in a gyro underspin "error" if gyro is spinning too slowly + const double spin_thresh = 0.8; + const double max_roll_error = 40.0; + const double max_pitch_error = 12.0; + const double max_hdg_error = 140.0; + double roll_error; + double pitch_error; + double hdg_error; - _indicated_roll_rate = indicated_roll_rate; - _indicated_pitch_rate = indicated_pitch_rate; - _indicated_hdg_rate = indicated_hdg_rate; + if ( spin <= spin_thresh ) { + double roll_error_factor = ( spin_thresh - spin ) / spin_thresh; + double pitch_error_factor = ( spin_thresh - spin ) / spin_thresh; + double hdg_error_factor = ( spin_thresh - spin ) / spin_thresh; + roll_error = roll_error_factor * roll_error_factor * max_roll_error; + pitch_error = pitch_error_factor * pitch_error_factor * max_pitch_error; + hdg_error = hdg_error_factor * hdg_error_factor * max_hdg_error; + } else { + roll_error = 0.0; + pitch_error = 0.0; + hdg_error = 0.0; + } - // add in a gyro underspin "error" if gyro is spinning too slowly - const double spin_thresh = 0.8; - const double max_roll_error = 40.0; - const double max_pitch_error = 12.0; - const double max_hdg_error = 140.0; - double roll_error; - double pitch_error; - double hdg_error; - - if ( spin <= spin_thresh ) { - double roll_error_factor = ( spin_thresh - spin ) / spin_thresh; - double pitch_error_factor = ( spin_thresh - spin ) / spin_thresh; - double hdg_error_factor = ( spin_thresh - spin ) / spin_thresh; - roll_error = roll_error_factor * roll_error_factor * max_roll_error; - pitch_error = pitch_error_factor * pitch_error_factor * max_pitch_error; - hdg_error = hdg_error_factor * hdg_error_factor * max_hdg_error; - } else { - roll_error = 0.0; - pitch_error = 0.0; - hdg_error = 0.0; - } - - _roll_out_node->setDoubleValue( _indicated_roll + roll_error ); - _pitch_out_node->setDoubleValue( _indicated_pitch + pitch_error ); - _hdg_out_node->setDoubleValue( _indicated_hdg + hdg_error ); - _pitch_rate_out_node ->setDoubleValue( _indicated_pitch_rate ); - _roll_rate_out_node ->setDoubleValue( _indicated_roll_rate ); - _hdg_rate_out_node ->setDoubleValue( _indicated_hdg_rate ); + _roll_out_node->setDoubleValue( _indicated_roll + roll_error ); + _pitch_out_node->setDoubleValue( _indicated_pitch + pitch_error ); + _hdg_out_node->setDoubleValue( _indicated_hdg + hdg_error ); + _pitch_rate_out_node ->setDoubleValue( _indicated_pitch_rate ); + _roll_rate_out_node ->setDoubleValue( _indicated_roll_rate ); + _hdg_rate_out_node ->setDoubleValue( _indicated_hdg_rate ); } // end of mrg.cxx diff --git a/src/Instrumentation/mrg.hxx b/src/Instrumentation/mrg.hxx index 4fc8fdee3..b925353a5 100644 --- a/src/Instrumentation/mrg.hxx +++ b/src/Instrumentation/mrg.hxx @@ -49,6 +49,8 @@ public: private: + static const double gravity; //conversion factor + string _name; int _num; @@ -66,6 +68,7 @@ private: double _last_yaw_rate; double _last_g; double _erect_time; + double _g_error; Gyro _gyro; diff --git a/src/Main/CameraGroup.cxx b/src/Main/CameraGroup.cxx index 0fb2f2e56..305c68363 100644 --- a/src/Main/CameraGroup.cxx +++ b/src/Main/CameraGroup.cxx @@ -35,10 +35,15 @@ #include #include +#include #include +#include #include #include +#include +#include #include +#include #include #include @@ -148,7 +153,18 @@ CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera, // resized; if the the viewport isn't copied here, it gets updated // twice and ends up with the wrong value. farCamera->setViewport(simgear::clone(camera->getViewport())); - _viewer->addSlave(farCamera, view, projection, useMasterSceneData); + farCamera->setDrawBuffer(camera->getDrawBuffer()); + farCamera->setReadBuffer(camera->getReadBuffer()); + farCamera->setRenderTargetImplementation( + camera->getRenderTargetImplementation()); + const Camera::BufferAttachmentMap& bufferMap + = camera->getBufferAttachmentMap(); + if (bufferMap.count(Camera::COLOR_BUFFER) != 0) { + farCamera->attach( + Camera::COLOR_BUFFER, + bufferMap.find(Camera::COLOR_BUFFER)->second._texture); + } + _viewer->addSlave(farCamera, projection, view, useMasterSceneData); installCullVisitor(farCamera); info->farCamera = farCamera; info->farSlaveIndex = _viewer->getNumSlaves() - 1; @@ -156,7 +172,7 @@ CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera, camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT); camera->setClearMask(GL_DEPTH_BUFFER_BIT); } - _viewer->addSlave(camera, view, projection, useMasterSceneData); + _viewer->addSlave(camera, projection, view, useMasterSceneData); installCullVisitor(camera); info->camera = camera; info->slaveIndex = _viewer->getNumSlaves() - 1; @@ -297,6 +313,199 @@ void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode, namespace flightgear { +// Mostly copied from osg's osgViewer/View.cpp + +static osg::Geometry* createParoramicSphericalDisplayDistortionMesh( + const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector, + double sphere_radius, double collar_radius, + Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix()) +{ + osg::Vec3d center(0.0,0.0,0.0); + osg::Vec3d eye(0.0,0.0,0.0); + + double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius); + bool flip = false; + bool texcoord_flip = false; + + osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance); + +#if 0 + OSG_INFO<<"createParoramicSphericalDisplayDistortionMesh : Projector position = "<getStringValue(); + TextureMap::iterator itr = _textureTargets.find(texName); + if (itr == _textureTargets.end()) { + // error + return; + } + Viewport* viewport = camera->getViewport(); + float width = viewport->width(); + float height = viewport->height(); + TextureRectangle* texRect = itr->second.get(); + double radius = psNode->getDoubleValue("radius", 1.0); + double collar = psNode->getDoubleValue("collar", 0.45); + Geode* geode = new Geode(); + geode->addDrawable(createParoramicSphericalDisplayDistortionMesh( + Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f), + Vec3(0.0f,height,0.0f), radius, collar)); + + // new we need to add the texture to the mesh, we do so by creating a + // StateSet to contain the Texture StateAttribute. + StateSet* stateset = geode->getOrCreateStateSet(); + stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON); + stateset->setMode(GL_LIGHTING, StateAttribute::OFF); + + TexMat* texmat = new TexMat; + texmat->setScaleByTextureRectangleSize(true); + stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON); +#if 0 + if (!applyIntensityMapAsColours && intensityMap) + { + stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON); + } +#endif + // add subgraph to render + camera->addChild(geode); + camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0)); + camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); + camera->setCullingMode(osg::CullSettings::NO_CULLING); + camera->setName("DistortionCorrectionCamera"); +} + CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode) { WindowBuilder *wBuild = WindowBuilder::getWindowBuilder(); @@ -390,13 +599,43 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode) double sheary = cameraNode->getDoubleValue("shear-y", 0); pOff.makeTranslate(-shearx, -sheary, 0); } - CameraInfo* info = addCamera(cameraFlags, camera, pOff, vOff); + const SGPropertyNode* textureNode = cameraNode->getNode("texture"); + if (textureNode) { + string texName = textureNode->getStringValue("name"); + int tex_width = textureNode->getIntValue("width"); + int tex_height = textureNode->getIntValue("height"); + TextureRectangle* texture = new TextureRectangle; + + texture->setTextureSize(tex_width, tex_height); + texture->setInternalFormat(GL_RGB); + texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR); + texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR); + texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE); + texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE); + camera->setDrawBuffer(GL_FRONT); + camera->setReadBuffer(GL_FRONT); + camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT); + camera->attach(Camera::COLOR_BUFFER, texture); + _textureTargets[texName] = texture; + } else { + camera->setDrawBuffer(GL_BACK); + camera->setReadBuffer(GL_BACK); + } + const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical"); + bool useMasterSceneGraph = !psNode; + CameraInfo* info = addCamera(cameraFlags, camera, vOff, pOff, + useMasterSceneGraph); // If a viewport isn't set on the camera, then it's hard to dig it // out of the SceneView objects in the viewer, and the coordinates // of mouse events are somewhat bizzare. SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true); buildViewport(info, viewportNode, window->gc->getTraits()); updateCameras(info); + // Distortion camera needs the viewport which is created by addCamera(). + if (psNode) { + info->flags = info->flags | VIEW_ABSOLUTE; + buildDistortionCamera(psNode, camera); + } return info; } diff --git a/src/Main/CameraGroup.hxx b/src/Main/CameraGroup.hxx index 79d0d33d4..1e18e28e1 100644 --- a/src/Main/CameraGroup.hxx +++ b/src/Main/CameraGroup.hxx @@ -17,6 +17,7 @@ #ifndef CAMERAGROUP_HXX #define CAMERAGROUP_HXX 1 +#include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include // For osgUtil::LineSegmentIntersector::Intersections, which is a typedef. #include @@ -178,6 +180,9 @@ public: /** Update camera properties after a resize event. */ void resized(); + + void buildDistortionCamera(const SGPropertyNode* psNode, + osg::Camera* camera); protected: CameraList _cameras; osg::ref_ptr _viewer; @@ -186,6 +191,8 @@ protected: float _zNear; float _zFar; float _nearField; + typedef std::map > TextureMap; + TextureMap _textureTargets; }; } diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index e9592c14e..8f66da05d 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -589,7 +589,7 @@ public: bool loadAircraft() { - std::string aircraft = fgGetString( "/sim/aircraft", ""); + std::string aircraft = fgGetString( "/sim/aircraft", ""); if (aircraft.empty()) { SG_LOG(SG_GENERAL, SG_ALERT, "no aircraft specified"); return false; @@ -601,6 +601,9 @@ public: SGPropertyNode *n = _cache->getNode("fg-root", true); n->setStringValue(globals->get_fg_root().c_str()); n->setAttribute(SGPropertyNode::USERARCHIVE, true); + n = _cache->getNode("fg-aircraft", true); + n->setStringValue(getAircraftPaths().c_str()); + n->setAttribute(SGPropertyNode::USERARCHIVE, true); _cache->removeChildren("aircraft"); fgFindAircraft(this, &FindAndCacheAircraft::checkAircraft); @@ -629,11 +632,29 @@ public: } private: + SGPath getAircraftPaths() { + string_list pathList = globals->get_aircraft_paths(); + SGPath aircraftPaths; + string_list::const_iterator it = pathList.begin(); + if (it != pathList.end()) { + aircraftPaths.set(*it); + it++; + } + for (; it != pathList.end(); ++it) { + aircraftPaths.add(*it); + } + return aircraftPaths; + } + bool checkCache() { if (globals->get_fg_root() != _cache->getStringValue("fg-root", "")) { return false; // cache mismatch } + + if (getAircraftPaths().str() != _cache->getStringValue("fg-aircraft", "")) { + return false; // cache mismatch + } vector cache = _cache->getChildren("aircraft"); for (unsigned int i = 0; i < cache.size(); i++) { diff --git a/src/Scenery/SceneryPager.cxx b/src/Scenery/SceneryPager.cxx index e23a71d26..183511361 100644 --- a/src/Scenery/SceneryPager.cxx +++ b/src/Scenery/SceneryPager.cxx @@ -33,7 +33,6 @@ SceneryPager::SceneryPager() { _pagerRequests.reserve(48); _deleteRequests.reserve(16); - setExpiryDelay(120.0); } SceneryPager::SceneryPager(const SceneryPager& rhs) :