]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/viewer.cxx
Improve timing statistics
[flightgear.git] / src / Main / viewer.cxx
index 6a9d99661eaa60de9ad01ed8e839d8067a50a758..57e60f48110007c8eff18f06cd0f8fc05f2271b9 100644 (file)
 #endif
 
 #include <simgear/compiler.h>
+#include <cassert>
 
 #include "fg_props.hxx"
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/constants.h>
 #include <simgear/scene/model/placement.hxx>
-#include <simgear/math/vector.hxx>
 
 #include <Main/globals.hxx>
 #include <Scenery/scenery.hxx>
@@ -64,10 +64,6 @@ FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
     _roll_deg(0),
     _pitch_deg(0),
     _heading_deg(0),
-    _damp_sync(0),
-    _damp_roll(0),
-    _damp_pitch(0),
-    _damp_heading(0),
     _scaling_type(FG_SCALING_MAX),
     _aspect_ratio(0),
     _cameraGroup(CameraGroup::getDefault())
@@ -81,12 +77,16 @@ FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
 
     _internal = internal;
 
+    _dampFactor = SGVec3d::zeros();
+    _dampOutput = SGVec3d::zeros();
+    _dampTarget = SGVec3d::zeros();
+    
     if (damp_roll > 0.0)
-      _damp_roll = 1.0 / pow(10.0, fabs(damp_roll));
+      _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
     if (damp_pitch > 0.0)
-      _damp_pitch = 1.0 / pow(10.0, fabs(damp_pitch));
+      _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
     if (damp_heading > 0.0)
-      _damp_heading = 1.0 / pow(10.0, fabs(damp_heading));
+      _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
 
     _offset_m.x() = x_offset_m;
     _offset_m.y() = y_offset_m;
@@ -289,7 +289,14 @@ void
 FGViewer::setHeadingOffset_deg (double heading_offset_deg)
 {
   _dirty = true;
-  _heading_offset_deg = heading_offset_deg;
+  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+  {
+      /* avoid optical effects (e.g. rotating sky) when "looking at" with
+       * heading offsets x==z==0 (view heading cannot change). */
+      _heading_offset_deg = 0.0;
+  }
+  else
+      _heading_offset_deg = heading_offset_deg;
 }
 
 void
@@ -317,6 +324,14 @@ void
 FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
 {
   _dirty = true;
+  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+  {
+      /* avoid optical effects (e.g. rotating sky) when "looking at" with
+       * heading offsets x==z==0 (view heading cannot change). */
+      _goal_heading_offset_deg = 0.0;
+      return;
+  }
+  
   _goal_heading_offset_deg = goal_heading_offset_deg;
   while ( _goal_heading_offset_deg < 0.0 ) {
     _goal_heading_offset_deg += 360;
@@ -369,29 +384,35 @@ FGViewer::recalcLookFrom ()
   double roll = _roll_deg;
   if ( !_from_model ) {
     // update from our own data...
-    dampEyeData(roll, pitch, head);
+    setDampTarget(roll, pitch, head);
+    getDampOutput(roll, pitch, head);
   }
 
   // The rotation rotating from the earth centerd frame to
-  // the horizontal local OpenGL frame
-  SGQuatd hlOr = SGQuatd::viewHL(_position);
+  // the horizontal local frame
+  SGQuatd hlOr = SGQuatd::fromLonLat(_position);
 
-  // the rotation from the horizontal local frame to the basic view orientation
+  // The rotation from the horizontal local frame to the basic view orientation
   SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
-  hlToBody = SGQuatd::simToView(hlToBody);
 
-  // The cartesian position of the basic view coordinate
-  SGVec3d position = SGVec3d::fromGeod(_position);
-  // the rotation offset, don't know why heading is negative here ...
-  SGQuatd viewOffsetOr = SGQuatd::simToView(
-    SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
-                                 _roll_offset_deg));
+  // The rotation offset, don't know why heading is negative here ...
+  mViewOffsetOr
+      = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
+                                     _roll_offset_deg);
 
   // Compute the eyepoints orientation and position
   // wrt the earth centered frame - that is global coorinates
   SGQuatd ec2body = hlOr*hlToBody;
-  _absolute_view_pos = position + ec2body.backTransform(_offset_m);
-  mViewOrientation = ec2body*viewOffsetOr;
+
+  // The cartesian position of the basic view coordinate
+  SGVec3d position = SGVec3d::fromGeod(_position);
+
+  // This is rotates the x-forward, y-right, z-down coordinate system the where
+  // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
+  SGQuatd q(-0.5, -0.5, 0.5, 0.5);
+
+  _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
+  mViewOrientation = ec2body*mViewOffsetOr*q;
 }
 
 void
@@ -406,13 +427,13 @@ FGViewer::recalcLookAt ()
     _target_roll_deg = placement->getRollDeg();
   } else {
     // if not model then calculate our own target position...
-    dampEyeData(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
-
+    setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+    getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
   }
 
   SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
-                                                      _target_pitch_deg,
-                                                      _target_roll_deg);
+                                                   _target_pitch_deg,
+                                                   _target_roll_deg);
   SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
 
 
@@ -424,15 +445,14 @@ FGViewer::recalcLookAt ()
     _roll_deg = placement->getRollDeg();
   } else {
     // update from our own data, just the rotation here...
-    dampEyeData(_roll_deg, _pitch_deg, _heading_deg);
+    setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
+    getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
   }
-  SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg,
-                                                   _pitch_deg,
-                                                   _roll_deg);
+  SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
   SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
 
   // the rotation offset, don't know why heading is negative here ...
-  SGQuatd eyeOffsetOr =
+  mViewOffsetOr =
     SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
                                  _roll_offset_deg);
 
@@ -440,7 +460,7 @@ FGViewer::recalcLookAt ()
   SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
   SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
   SGVec3d eyeCart = SGVec3d::fromGeod(_position);
-  eyeCart += (ec2eye*eyeOffsetOr).backTransform(eyeOff);
+  eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
 
   SGVec3d atCart = SGVec3d::fromGeod(_target);
 
@@ -459,67 +479,61 @@ FGViewer::recalcLookAt ()
   SGVec3d dir = normalize(atCart - eyeCart);
   // the up directon
   SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
-  // rotate dir to the 0-th unit vector
-  // rotate up to 2-th unit vector
+  // rotate -dir to the 2-th unit vector
+  // rotate up to 1-th unit vector
+  // Note that this matches the OpenGL camera coordinate system
+  // with x-right, y-up, z-back.
   mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
 }
 
 void
-FGViewer::dampEyeData(double &roll_deg, double &pitch_deg, double &heading_deg)
+FGViewer::setDampTarget(double roll, double pitch, double heading)
 {
-  const double interval = 0.01;
+  _dampTarget = SGVec3d(roll, pitch, heading);
+}
+
+void
+FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
+{
+  roll = _dampOutput[0];
+  pitch = _dampOutput[1];
+  heading = _dampOutput[2];
+}
+
 
+void
+FGViewer::updateDampOutput(double dt)
+{
   static FGViewer *last_view = 0;
-  if (last_view != this) {
-    _damp_sync = 0.0;
-    _damped_roll_deg = roll_deg;
-    _damped_pitch_deg = pitch_deg;
-    _damped_heading_deg = heading_deg;
+  if ((last_view != this) || (dt > 1.0)) {
+    _dampOutput = _dampTarget;
     last_view = this;
     return;
   }
-
-  if (_damp_sync < interval) {
-    if (_damp_roll > 0.0)
-      roll_deg = _damped_roll_deg;
-    if (_damp_pitch > 0.0)
-      pitch_deg = _damped_pitch_deg;
-    if (_damp_heading > 0.0)
-      heading_deg = _damped_heading_deg;
-    return;
-  }
-
-  while (_damp_sync >= interval) {
-    _damp_sync -= interval;
-
-    double d;
-    if (_damp_roll > 0.0) {
-      d = _damped_roll_deg - roll_deg;
-      if (d >= 180.0)
-        _damped_roll_deg -= 360.0;
-      else if (d < -180.0)
-        _damped_roll_deg += 360.0;
-      roll_deg = _damped_roll_deg = roll_deg * _damp_roll + _damped_roll_deg * (1 - _damp_roll);
-    }
-
-    if (_damp_pitch > 0.0) {
-      d = _damped_pitch_deg - pitch_deg;
-      if (d >= 180.0)
-        _damped_pitch_deg -= 360.0;
-      else if (d < -180.0)
-        _damped_pitch_deg += 360.0;
-      pitch_deg = _damped_pitch_deg = pitch_deg * _damp_pitch + _damped_pitch_deg * (1 - _damp_pitch);
-    }
-
-    if (_damp_heading > 0.0) {
-      d = _damped_heading_deg - heading_deg;
-      if (d >= 180.0)
-        _damped_heading_deg -= 360.0;
-      else if (d < -180.0)
-        _damped_heading_deg += 360.0;
-      heading_deg = _damped_heading_deg = heading_deg * _damp_heading + _damped_heading_deg * (1 - _damp_heading);
-    }
-  }
+  
+  const double interval = 0.01;
+  while (dt > interval) {
+    
+    for (unsigned int i=0; i<3; ++i) {
+      if (_dampFactor[i] <= 0.0) {
+        // axis is un-damped, set output to target directly
+        _dampOutput[i] = _dampTarget[i];
+        continue;
+      }
+      
+      double d = _dampOutput[i] - _dampTarget[i];
+      if (d > 180.0) {
+        _dampOutput[i] -= 360.0;
+      } else if (d < -180.0) {
+        _dampOutput[i] += 360.0;
+      }
+      
+      _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) + 
+        (_dampOutput[i] * (1.0 - _dampFactor[i]));
+    } // of axis iteration
+    
+    dt -= interval;
+  } // of dt subdivision by interval
 }
 
 double
@@ -576,8 +590,8 @@ FGViewer::get_v_fov()
 void
 FGViewer::update (double dt)
 {
-  _damp_sync += dt;
-
+  updateDampOutput(dt);
+  
   int i;
   int dt_ms = int(dt * 1000);
   for ( i = 0; i < dt_ms; i++ ) {
@@ -652,6 +666,8 @@ FGViewer::update (double dt)
     }
   }
   recalc();
-  _cameraGroup->update(_absolute_view_pos.osg(), mViewOrientation.osg());
-  _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
+  if( fgGetBool( "/sim/rendering/draw-otw", true ) ) {
+    _cameraGroup->update(toOsg(_absolute_view_pos), toOsg(mViewOrientation));
+    _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
+  }
 }