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