]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/viewmgr.cxx
Juggle fgfs link order to keep GNU ld happy.
[flightgear.git] / src / Main / viewmgr.cxx
index e64f1d13f85fc6b23e9732b071e157684a3257c3..270c579e03b82dcfd89457b8a8dd9b472bead2d5 100644 (file)
 #  include "config.h"
 #endif
 
-#include <string.h>            // strcmp
+#include "viewmgr.hxx"
 
-#include <plib/sg.h>
+#include <string.h>            // strcmp
 
 #include <simgear/compiler.h>
-
+#include <simgear/sound/soundmgr_openal.hxx>
 #include <Model/acmodel.hxx>
-
-#include "viewmgr.hxx"
-
+#include <Main/viewer.hxx>
+#include <Main/fg_props.hxx>
 
 // Constructor
 FGViewMgr::FGViewMgr( void ) :
   axis_long(0),
   axis_lat(0),
+  view_number(fgGetNode("/sim/current-view/view-number", true)),
   config_list(fgGetNode("/sim", true)->getChildren("view")),
   current(0)
 {
+    smgr = globals->get_soundmgr();
 }
 
 // Destructor
@@ -74,11 +75,11 @@ FGViewMgr::init ()
     double z_offset_m = n->getDoubleValue("config/z-offset-m");
 
     double heading_offset_deg = n->getDoubleValue("config/heading-offset-deg");
-    n->setDoubleValue(heading_offset_deg);
+    n->setDoubleValue("config/heading-offset-deg", heading_offset_deg);
     double pitch_offset_deg = n->getDoubleValue("config/pitch-offset-deg");
-    n->setDoubleValue(pitch_offset_deg);
+    n->setDoubleValue("config/pitch-offset-deg", pitch_offset_deg);
     double roll_offset_deg = n->getDoubleValue("config/roll-offset-deg");
-    n->setDoubleValue(roll_offset_deg);
+    n->setDoubleValue("config/roll-offset-deg", roll_offset_deg);
 
     double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
     double near_m = n->getDoubleValue("config/ground-level-nearplane-m");
@@ -146,11 +147,11 @@ FGViewMgr::reinit ()
     fgSetDouble("/sim/current-view/field-of-view", fov_deg);
 
     // target offsets for lookat mode only...
-    fgSetDouble("/sim/current-view/target-x-offset-deg",
+    fgSetDouble("/sim/current-view/target-x-offset-m",
         n->getDoubleValue("config/target-x-offset-m"));
-    fgSetDouble("/sim/current-view/target-y-offset-deg",
+    fgSetDouble("/sim/current-view/target-y-offset-m",
         n->getDoubleValue("config/target-y-offset-m"));
-    fgSetDouble("/sim/current-view/target-z-offset-deg",
+    fgSetDouble("/sim/current-view/target-z-offset-m",
         n->getDoubleValue("config/target-z-offset-m"));
   }
   setView(0);
@@ -211,6 +212,42 @@ FGViewMgr::bind ()
        &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
   fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
 
+  SGPropertyNode *n = fgGetNode("/sim/current-view", true);
+  n->tie("viewer-x-m", SGRawValuePointer<double>(&abs_viewer_position[0]));
+  n->tie("viewer-y-m", SGRawValuePointer<double>(&abs_viewer_position[1]));
+  n->tie("viewer-z-m", SGRawValuePointer<double>(&abs_viewer_position[2]));
+
+// for automatic untying:
+#define x(str) ((void)tied_props.push_back(str), str)
+
+  fgTie(x("/sim/current-view/debug/orientation-w"), this,
+       &FGViewMgr::getCurrentViewOrientation_w);
+  fgTie(x("/sim/current-view/debug/orientation-x"), this,
+        &FGViewMgr::getCurrentViewOrientation_x);
+  fgTie(x("/sim/current-view/debug/orientation-y"), this,
+        &FGViewMgr::getCurrentViewOrientation_y);
+  fgTie(x("/sim/current-view/debug/orientation-z"), this,
+        &FGViewMgr::getCurrentViewOrientation_z);
+
+  fgTie(x("/sim/current-view/debug/orientation_offset-w"), this,
+       &FGViewMgr::getCurrentViewOrOffset_w);
+  fgTie(x("/sim/current-view/debug/orientation_offset-x"), this,
+        &FGViewMgr::getCurrentViewOrOffset_x);
+  fgTie(x("/sim/current-view/debug/orientation_offset-y"), this,
+        &FGViewMgr::getCurrentViewOrOffset_y);
+  fgTie(x("/sim/current-view/debug/orientation_offset-z"), this,
+        &FGViewMgr::getCurrentViewOrOffset_z);
+
+  fgTie(x("/sim/current-view/debug/frame-w"), this,
+       &FGViewMgr::getCurrentViewFrame_w);
+  fgTie(x("/sim/current-view/debug/frame-x"), this,
+        &FGViewMgr::getCurrentViewFrame_x);
+  fgTie(x("/sim/current-view/debug/frame-y"), this,
+        &FGViewMgr::getCurrentViewFrame_y);
+  fgTie(x("/sim/current-view/debug/frame-z"), this,
+        &FGViewMgr::getCurrentViewFrame_z);
+
+#undef x
 }
 
 void
@@ -228,16 +265,24 @@ FGViewMgr::unbind ()
   fgUntie("/sim/current-view/axes/long");
   fgUntie("/sim/current-view/axes/lat");
   fgUntie("/sim/current-view/ground-level-nearplane-m");
+  fgUntie("/sim/current-view/viewer-x-m");
+  fgUntie("/sim/current-view/viewer-y-m");
+  fgUntie("/sim/current-view/viewer-z-m");
+
+  list<const char*>::const_iterator it;
+  for (it = tied_props.begin(); it != tied_props.end(); it++){
+    fgUntie(*it);
+  }
+
 }
 
 void
 FGViewMgr::update (double dt)
 {
-  FGViewer * view = get_current_view();
-  if (view == 0)
-    return;
 
-  FGViewer *loop_view = (FGViewer *)get_view(current);
+  FGViewer *loop_view = (FGViewer *)get_current_view();
+  if (loop_view == 0) return;
+
   SGPropertyNode *n = config_list[current];
   double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
 
@@ -283,15 +328,33 @@ FGViewMgr::update (double dt)
   setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
   setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
 
+  current_view_orientation = loop_view->getViewOrientation();
+  current_view_or_offset = loop_view->getViewOrientationOffset();
+
   // Update the current view
   do_axes();
-  view->update(dt);
+  loop_view->update(dt);
+  abs_viewer_position = loop_view->getViewPosition();
+
+  // update audio listener values
+  // set the viewer posotion in Cartesian coordinates in meters
+  smgr->set_position( abs_viewer_position, loop_view->getPosition() );
+  smgr->set_orientation( current_view_orientation );
+
+  // get the model velocity
+  SGVec3d velocity = SGVec3d::zeros();
+  if ( !stationary() ) {
+    velocity = globals->get_aircraft_model()->getVelocity();
+  }
+  smgr->set_velocity( velocity );
 }
 
 void
 FGViewMgr::copyToCurrent()
 {
     SGPropertyNode *n = config_list[current];
+    fgSetString("/sim/current-view/name", n->getStringValue("name"));
+    fgSetString("/sim/current-view/type", n->getStringValue("type"));
 
     // copy certain view config data for default values
     fgSetDouble("/sim/current-view/config/heading-offset-deg",
@@ -332,7 +395,71 @@ FGViewMgr::copyToCurrent()
                 get_current_view()->getInternal());
 }
 
+void FGViewMgr::clear()
+{
+  views.clear();
+}
+
+FGViewer*
+FGViewMgr::get_current_view()
+{
+       if ( current < (int)views.size() ) {
+           return views[current];
+       } else {
+           return NULL;
+       }
+}
 
+const FGViewer*
+FGViewMgr::get_current_view() const
+{
+       if ( current < (int)views.size() ) {
+           return views[current];
+       } else {
+           return NULL;
+       }
+}
+
+
+FGViewer*
+FGViewMgr::get_view( int i )
+{
+       if ( i < 0 ) { i = 0; }
+       if ( i >= (int)views.size() ) { i = views.size() - 1; }
+       return views[i];
+}
+
+const FGViewer*
+FGViewMgr::get_view( int i ) const
+{
+       if ( i < 0 ) { i = 0; }
+       if ( i >= (int)views.size() ) { i = views.size() - 1; }
+       return views[i];
+}
+
+FGViewer*
+FGViewMgr::next_view()
+{
+       setView((current+1 < (int)views.size()) ? (current + 1) : 0);
+       view_number->fireValueChanged();
+       return views[current];
+}
+
+FGViewer*
+FGViewMgr::prev_view()
+{
+       setView((0 < current) ? (current - 1) : (views.size() - 1));
+       view_number->fireValueChanged();
+       return views[current];
+}
+
+void
+FGViewMgr::add_view( FGViewer * v )
+{
+  views.push_back(v);
+  v->init();
+}
+    
 double
 FGViewMgr::getViewHeadingOffset_deg () const
 {
@@ -489,6 +616,20 @@ FGViewMgr::setViewZOffset_m (double z)
   }
 }
 
+bool
+FGViewMgr::stationary () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
+        ((FGViewer *)view)->getYOffset_m() == 0.0 &&
+        ((FGViewer *)view)->getZOffset_m() == 0.0)
+      return true;
+  }
+
+  return false;
+}
+
 double
 FGViewMgr::getViewTargetXOffset_m () const
 {
@@ -561,20 +702,20 @@ FGViewMgr::setView (int newview)
   // negative numbers -> set view with node index -newview
   if (newview < 0) {
     for (int i = 0; i < (int)config_list.size(); i++) {
-        int index = -config_list[i]->getIndex();
-        if (index == newview)
-            newview = i;
+      int index = -config_list[i]->getIndex();
+      if (index == newview)
+        newview = i;
     }
     if (newview < 0)
-        return;
+      return;
   }
 
   // if newview number too low wrap to last view...
   if (newview < 0)
-    newview = (int)views.size() -1;
+    newview = (int)views.size() - 1;
 
   // if newview number to high wrap to zero...
-  if (newview > ((int)views.size() -1))
+  if (newview >= (int)views.size())
     newview = 0;
 
   // set new view
@@ -647,6 +788,101 @@ FGViewMgr::setViewAxisLat (double axis)
   axis_lat = axis;
 }
 
+// reference frame orientation.
+// This is the view orientation you get when you have no
+// view offset, i.e. the offset operator is the identity.
+// 
+// For example, in the familiar "cockpit lookfrom" view,
+// the reference frame is equal to the aircraft attitude,
+// i.e. it is the view looking towards 12:00 straight ahead.
+//
+// FIXME:  Somebody needs to figure out what is the reference
+// frame view for the other view modes.
+// 
+// Conceptually, this quat represents a rotation relative
+// to the ECEF reference orientation, as described at
+//    http://www.av8n.com/physics/coords.htm#sec-orientation
+//
+// See the NOTE concerning reference orientations, below.
+//
+// The components of this quat are expressed in 
+// the conventional aviation basis set,
+// i.e.  x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewFrame_w() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
+}
+double FGViewMgr::getCurrentViewFrame_x() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
+}
+double FGViewMgr::getCurrentViewFrame_y() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
+}
+double FGViewMgr::getCurrentViewFrame_z() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
+}
+
+
+// view offset.
+// This rotation takes you from the aforementioned
+// reference frame view orientation to whatever
+// actual current view orientation is.
+//
+// The components of this quaternion are expressed in 
+// the conventional aviation basis set,
+// i.e.  x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewOrOffset_w() const{
+   return current_view_or_offset.w();
+}
+double FGViewMgr::getCurrentViewOrOffset_x() const{
+   return current_view_or_offset.x();
+}
+double FGViewMgr::getCurrentViewOrOffset_y() const{
+   return current_view_or_offset.y();
+}
+double FGViewMgr::getCurrentViewOrOffset_z() const{
+   return current_view_or_offset.z();
+}
+
+
+// current view orientation.
+// This is a rotation relative to the earth-centered (ec)
+// reference frame.
+// 
+// NOTE: Here we remove a factor of fsb2sta so that 
+// the components of this quat are displayed using the 
+// conventional ECEF basis set.  This is *not* the way
+// the view orientation is stored in the views[] array,
+// but is easier for non-graphics hackers to understand.
+// If we did not remove this factor of fsb2sta here and
+// in getCurrentViewFrame, that would be equivalent to
+// the following peculiar reference orientation:
+// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
+// Then the reference frame orientation can be achieved via:
+//    -- The aircraft X-axis (nose) headed south.
+//    -- The aircraft Y-axis (starboard wingtip) pointing up.
+//    -- The aircraft Z-axis (belly) pointing west.
+// To say the same thing in other words, and perhaps more to the
+// point:  If we use the OpenGL camera orientation conventions, 
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
+// aforementioned peculiar reference orientation at (lat,lon)
+//  = (0,0) can be described as:
+//    -- aircraft Xprime axis (starboard) pointed up
+//    -- aircraft Yprime axis (top) pointed east
+//    -- aircraft Zprime axis (aft) pointed north
+// meaning the OpenGL axes are aligned with the ECEF axes.
+double FGViewMgr::getCurrentViewOrientation_w() const{
+  return (current_view_orientation * conj(fsb2sta())).w();
+}
+double FGViewMgr::getCurrentViewOrientation_x() const{
+  return (current_view_orientation * conj(fsb2sta())).x();
+}
+double FGViewMgr::getCurrentViewOrientation_y() const{
+  return (current_view_orientation * conj(fsb2sta())).y();
+}
+double FGViewMgr::getCurrentViewOrientation_z() const{
+  return (current_view_orientation * conj(fsb2sta())).z();
+}
+
 void
 FGViewMgr::do_axes ()
 {