]> git.mxchange.org Git - flightgear.git/commitdiff
Major viewer-code overhaul from Jim Wilson:
authordavid <david>
Wed, 20 Mar 2002 17:43:28 +0000 (17:43 +0000)
committerdavid <david>
Wed, 20 Mar 2002 17:43:28 +0000 (17:43 +0000)
Description:

This update includes the new viewer interface as proposed by David M. and
a first pass at cleaning up the viewer/view manager code by Jim W.

Note that I have dropped Main/viewer_lookat.?xx and Main/viewer_rph.?xx and
modified the Makefile.am accordingly.

Detail of work:

Overall:
The code reads a little easier.  There are still some unnecessary bits in
there and I'd like to supplement the comments in the viewer.hxx with a tiny
bit on each interface group and what the groupings mean (similar but briefer
than what you emailed me the other day).  I tried not to mess up the style,
but there is an occasional inconsistency.  In general I wouldn't call it done
(especially since there's no tower yet! :)), but I'd like to get this out
there so others can comment, and test.

In Viewer:
The interface as you suggested has been implemented.  Basically everything
seems to work as it did visually.  There is no difference that I can see in
performance, although some things might be a tiny bit faster.

I've merged the lookat and rph (pilot view) code into the recalc for the
viewer.  There is still some redundancy between the two, but a lot has been
removed.  In some cases I've taken some code that we'd likely want to inline
anyway and left it in there in duplicate.  You'll see that the code for both
looks a little cleaner.  I need to take a closer look at the rotations in
particular.  I've cleaned up a little there, but I suspect more can be done
to streamline this.

The external declaration to the Quat_mat in mouse.cxx has been removed.  IMHO
the quat doesn't serve any intrinsic purpose in mouse.cxx, but I'm not about
to rip it out.  It would seem that there more conventional ways to get
spherical data that are just as fast.  In any case all the viewer was pulling
from the quat matrix was the pitch value so I modified mouse.cxx to output to
our pitchOffset input and that works fine.

I've changed the native values to degrees from radians where appropriate.
This required a conversion from degrees to radians in a couple modules that
access the interface.  Perhaps we should add interface calls that do the
conversion,  e.g. a getHeadingOffset_rad() to go along with the
getHeadingOffset_deg().

On the view_offset (now headingOffset) thing there are two entry points
because of the ability to instantly switch views or to scroll to a new view
angle (by hitting the numeric keys for example).   This leaves an anomaly in
the interface which should be resolved by adding "goal" settings to the
interface, e.g. a setGoalHeadingOffset_deg(), setGoalPitchOffset_deg(), etc.

Other than these two issues, the next step here will be to look at some
further optimizations, and to write support code for a tower view.  That
should be fairly simple at this point.  I was considering creating a
"simulated tower view" or "pedestrian view" that defaulted to a position off
to the right of whereever the plane is at the moment you switch to the tower
view.  This could be a fall back when we don't have an actual tower location
at hand (as would be the case with rural airports).

ViewManager:
Basically all I did here was neaten things up by ripping out excess crap and
made it compatible as is with the new interface.

The result is that viewmanager is now ready to be developed.  The two
preexisting views are still hardcoded into the view manager.  The next step
would be to design configuration xml (eg /sim/view[x]/config/blahblah) that
could be used to set up as many views as we want.  If we want to take the easy
way out, we might want to insist that view[0] be a pilot-view and have
viewmanager check for that.

14 files changed:
src/Cockpit/cockpit.cxx
src/Cockpit/panel.cxx
src/GUI/mouse.cxx
src/Main/Makefile.am
src/Main/fg_commands.cxx
src/Main/model.cxx
src/Main/options.cxx
src/Main/viewer.cxx
src/Main/viewer.hxx
src/Main/viewmgr.cxx
src/Main/viewmgr.hxx
src/Scenery/newcache.cxx
src/Scenery/tilemgr.cxx
src/Time/light.cxx

index 5750035af27260a1f76e5f3b9d58480b36aa6701..afbdb314017e97cff5c1429ba0c68006975e112a 100644 (file)
@@ -259,7 +259,7 @@ float get_climb_rate( void )
 
 float get_view_direction( void )
 {
-    double view_off = SGD_2PI - globals->get_current_view()->get_view_offset();
+    double view_off = SGD_2PI - globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS;
     double view = ( current_aircraft.fdm_state->get_Psi() + view_off)
        * SGD_RADIANS_TO_DEGREES;
     
@@ -745,3 +745,4 @@ void fgCockpitUpdate( void ) {
     
     glViewport( 0, 0, iwidth, iheight );
 }
+
index ab0ce21428cfe776e4810cfdb87be48d22d8ffe3..5443c0437d373f682ff6817f2af5dfc11bf06290 100644 (file)
@@ -89,7 +89,7 @@ fgPanelVisible ()
        return false;
      if(globals->get_viewmgr()->get_current() != 0)
        return false;
-     if(globals->get_current_view()->get_view_offset() != 0 &&
+     if(globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS != 0 &&
         !fgGetBool("/sim/virtual-cockpit"))
        return false;
      return true;
@@ -452,8 +452,8 @@ FGPanel::setupVirtualCockpit()
     // Generate a "look at" matrix using OpenGL (!) coordinate
     // conventions.
     float lookat[3];
-    float pitch = view->get_view_tilt();
-    float rot = view->get_view_offset();
+    float pitch = view->getPitchOffset_deg() * SGD_DEGREES_TO_RADIANS;
+    float rot = view->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS;
     lookat[0] = -sin(rot);
     lookat[1] = sin(pitch) / cos(pitch);
     lookat[2] = -cos(rot);
@@ -1150,3 +1150,4 @@ FGSwitchLayer::draw ()
 // end of panel.cxx
 
 
+
index fa6609c1e903d27db02e57386eaf89e89c5b730f..9e6fc7b26d5ba5478b56daddbe22caeb10f59f5e 100644 (file)
@@ -175,20 +175,30 @@ static inline int right_button( void ) {
 
 static inline void set_goal_view_offset( float offset )
 {
-       globals->get_current_view()->set_goal_view_offset(offset);
+       globals->get_current_view()->set_goal_view_offset(offset * SGD_RADIANS_TO_DEGREES);
 }
 
 static inline void set_view_offset( float offset )
 {
-       globals->get_current_view()->set_view_offset(offset);
+       globals->get_current_view()->setHeadingOffset_deg(offset * SGD_RADIANS_TO_DEGREES);
+}
+
+static inline void set_goal_view_tilt( float tilt )
+{
+       globals->get_current_view()->set_goal_view_tilt(tilt);
+}
+
+static inline void set_view_tilt( float tilt )
+{
+       globals->get_current_view()->setPitchOffset_deg(tilt);
 }
 
 static inline float get_view_offset() {
-       return globals->get_current_view()->get_view_offset();
+       return globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS;
 }
 
 static inline float get_goal_view_offset() {
-       return globals->get_current_view()->get_goal_view_offset();
+       return globals->get_current_view()->get_goal_view_offset() * SGD_DEGREES_TO_RADIANS;
 }
 
 static inline void move_brake(float offset) {
@@ -476,8 +486,10 @@ void guiMotionFunc ( int x, int y )
                     offset -= SGD_2PI;
                 }
                 set_goal_view_offset(offset);
+                set_goal_view_tilt(asin( GuiQuat_mat[1][2]) * SGD_RADIANS_TO_DEGREES );
 #ifdef NO_SMOOTH_MOUSE_VIEW
                 set_view_offset(offset);
+                set_view_tilt(asin( GuiQuat_mat[1][2]) * SGD_RADIANS_TO_DEGREES );
 #endif
                 break;
             
@@ -532,6 +544,7 @@ void guiMouseFunc(int button, int updown, int x, int y)
                         y = _Vy;
                         sgCopyVec4(curGuiQuat, _quat);
                         set_goal_view_offset(_view_offset);
+                        set_goal_view_tilt(0.0);
 #ifdef NO_SMOOTH_MOUSE_VIEW
                         set_view_offset(_view_offset);
 #endif
@@ -547,8 +560,10 @@ void guiMouseFunc(int button, int updown, int x, int y)
                         Quat0();
                         _view_offset = get_goal_view_offset();
                         set_goal_view_offset(0.0);
+                        set_goal_view_tilt(0.0);
 #ifdef NO_SMOOTH_MOUSE_VIEW
                         set_view_offset(0.0);
+                        set_view_tilt(0.0);
 #endif
                     }
                     glutWarpPointer( x , y);
@@ -605,8 +620,10 @@ void guiMouseFunc(int button, int updown, int x, int y)
                     Quat0();
                     build_rotmatrix(GuiQuat_mat, curGuiQuat);
                     set_goal_view_offset(0.0);
+                    set_goal_view_tilt(0.0);
 #ifdef NO_SMOOTH_MOUSE_VIEW
                     set_view_offset(0.0);
+                    set_view_tilt(0.0);
 #endif // NO_SMOOTH_MOUSE_VIEW
 #endif // RESET_VIEW_ON_LEAVING_MOUSE_VIEW
                     glutSetCursor(GLUT_CURSOR_INHERIT);
@@ -646,3 +663,5 @@ void guiMouseFunc(int button, int updown, int x, int y)
     glutPostRedisplay ();
 }
 
+
+
index 6324e2245c915427f069f745bbc8ed1ea48fc668..84feff63bfac4aa18e31fd1c6cf92491bfc948a8 100644 (file)
@@ -52,8 +52,6 @@ fgfs_SOURCES = \
        options.cxx options.hxx \
        splash.cxx splash.hxx \
        viewer.cxx viewer.hxx \
-       viewer_lookat.cxx viewer_lookat.hxx \
-       viewer_rph.cxx viewer_rph.hxx \
        viewmgr.cxx viewmgr.hxx
 
 fgfs_LDADD = \
@@ -95,3 +93,4 @@ INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src
 else
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
 endif
+
index 83eedd9feac72ca4a398a79d92daf50bde9e4b4b..9dac586d5770cc03290d8e660aada4ac01c28995 100644 (file)
@@ -242,7 +242,7 @@ do_preferences_load (const SGPropertyNode * arg, SGCommandState ** state)
 static bool
 do_view_cycle (const SGPropertyNode * arg, SGCommandState ** state)
 {
-  globals->get_current_view()->set_view_offset(0.0);
+  globals->get_current_view()->setHeadingOffset_deg(0.0);
   globals->get_viewmgr()->next_view();
   if ( fgGetString("/sim/flight-model") == "ada" ) {
       globals->get_props()->setBoolValue( "/sim/hud/visibility", true );
@@ -605,3 +605,4 @@ fgInitCommands ()
 }
 
 // end of fg_commands.hxx
+
index 8016f97ca3b6e5da9ac240e6d5158405ad210257..d4d8b9975b7155492ddd21fa068254460e81424f 100644 (file)
@@ -159,8 +159,8 @@ FGAircraftModel::update (int dt)
       do_animation(_animations[i], elapsed_ms);
 
     _selector->select(true);
-    FGViewerRPH *pilot_view =
-      (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
+    FGViewer *pilot_view =
+      (FGViewer *)globals->get_viewmgr()->get_view( 0 );
     
     sgMat4 sgTRANS;
     sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
@@ -178,15 +178,13 @@ FGAircraftModel::update (int dt)
     if (view_number == 0) {
                                // FIXME: orientation is not applied
                                // correctly when view is not forward
-      sgMakeRotMat4( sgROT, -pilot_view->get_view_offset()
-                    * SGD_RADIANS_TO_DEGREES, pilot_view->get_world_up() );
+      sgMakeRotMat4( sgROT, -pilot_view->getHeadingOffset_deg(), 
+         pilot_view->get_world_up() );
 
       /* Warning lame hack from Wilson ahead */
       /* get the pitch value */
-      sgVec3 rph;
-      sgCopyVec3(rph, pilot_view->get_rph());
       /* double it to counter the value already in the VIEW_ROT */
-      float pitch = rph[1] * 2;
+      float pitch = pilot_view->getPitch_deg() * SGD_DEGREES_TO_RADIANS * 2;
       /* make a ROT matrix 
          with the values waited by the X coordinate from the offset 
          rotation see sgROT above
@@ -383,3 +381,7 @@ FGAircraftModel::Animation::setRotation()
 
 
 // end of model.cxx
+
+
+
+
index 5ae407cd92e11c658a577116e7f43f433f4f1580..4d72d4101f846a8fac20058713e719361b995d15 100644 (file)
@@ -882,11 +882,11 @@ parse_option (const string& arg)
        } else {
            default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS;
        }
-       FGViewerRPH *pilot_view =
-           (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
-       pilot_view->set_view_offset( default_view_offset );
-       pilot_view->set_goal_view_offset( default_view_offset );
-       fgSetDouble("/sim/view/offset-deg", default_view_offset);
+       FGViewer *pilot_view =
+           (FGViewer *)globals->get_viewmgr()->get_view( 0 );
+       pilot_view->setHeadingOffset_deg( default_view_offset * SGD_RADIANS_TO_DEGREES );
+       pilot_view->set_goal_view_offset( default_view_offset * SGD_RADIANS_TO_DEGREES );
+       fgSetDouble("/sim/view/offset-deg", default_view_offset  * SGD_RADIANS_TO_DEGREES );
     // $$$ end - added VS Renganathan, 14 Oct 2K
     } else if ( arg.find( "--visibility=" ) == 0 ) {
        fgSetDouble("/environment/visibility-m", atof(arg.substr(13)));
@@ -1297,3 +1297,5 @@ fgUsage ()
          << "                                  instances allowed." << endl
          << endl;
 }
+
+
index 2628efc8feef10f63271dfae799ef2fd35ce59bd..1cdb8eb10d74b2d317b358af91b9464d451b8a89 100644 (file)
@@ -2,6 +2,8 @@
 //
 // Written by Curtis Olson, started August 1997.
 //                          overhaul started October 2000.
+//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+//                          by David Megginson March 2002
 //
 // Copyright (C) 1997 - 2000  Curtis L. Olson  - curt@flightgear.org
 //
 
 #include <Scenery/scenery.hxx>
 
-#include "viewer.hxx"
+/* from lookat */
+#include <simgear/math/vector.hxx>
+#include "globals.hxx"
+/* end from lookat */
 
+#include "viewer.hxx"
 
 \f
 ////////////////////////////////////////////////////////////////////////
-// Implementation of FGViewPoint.
+// Implementation of FGViewer.
 ////////////////////////////////////////////////////////////////////////
 
-FGViewPoint::FGViewPoint ()
-  : _dirty(true),
+// Constructor
+FGViewer::FGViewer( void ):
+    scalingType(FG_SCALING_MAX),
+    fov(55.0),
+    goal_view_offset(0.0),
+    goal_view_tilt(0.0),
+    _dirty(true),
     _lon_deg(0),
     _lat_deg(0),
-    _alt_ft(0)
+    _alt_ft(0),
+    _target_lon_deg(0),
+    _target_lat_deg(0),
+    _target_alt_ft(0),
+    _roll_deg(0),
+    _pitch_deg(0),
+    _heading_deg(0),
+    _x_offset_m(0),
+    _y_offset_m(0),
+    _z_offset_m(0),
+    _heading_offset_deg(0),
+    _pitch_offset_deg(0),
+    _roll_offset_deg(0)
+{
+    sgdZeroVec3(_absolute_view_pos);
+    sea_level_radius = SG_EQUATORIAL_RADIUS_M; 
+    //a reasonable guess for init, so that the math doesn't blow up
+}
+
+
+// Destructor
+FGViewer::~FGViewer( void ) {
+}
+
+void
+FGViewer::init ()
+{
+  if ( _type == FG_LOOKAT ) {
+      set_reverse_view_offset(true);
+  }
+
+  if ( _type == FG_RPH ) {
+      set_reverse_view_offset(false);
+  }
+}
+
+void
+FGViewer::bind ()
+{
+}
+
+void
+FGViewer::unbind ()
 {
 }
 
-FGViewPoint::~FGViewPoint ()
+void
+FGViewer::setType ( int type )
 {
+  if (type == 0)
+    _type = FG_RPH;
+  if (type == 1)
+    _type = FG_LOOKAT;
 }
 
 void
-FGViewPoint::setPosition (double lon_deg, double lat_deg, double alt_ft)
+FGViewer::setLongitude_deg (double lon_deg)
 {
   _dirty = true;
   _lon_deg = lon_deg;
+}
+
+void
+FGViewer::setLatitude_deg (double lat_deg)
+{
+  _dirty = true;
   _lat_deg = lat_deg;
+}
+
+void
+FGViewer::setAltitude_ft (double alt_ft)
+{
+  _dirty = true;
   _alt_ft = alt_ft;
 }
 
-const double *
-FGViewPoint::getAbsoluteViewPos () const
+void
+FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+  _dirty = true;
+  _lon_deg = lon_deg;
+  _lat_deg = lat_deg;
+  _alt_ft = alt_ft;
+}
+
+void
+FGViewer::setTargetLongitude_deg (double lon_deg)
+{
+  _dirty = true;
+  _target_lon_deg = lon_deg;
+}
+
+void
+FGViewer::setTargetLatitude_deg (double lat_deg)
+{
+  _dirty = true;
+  _target_lat_deg = lat_deg;
+}
+
+void
+FGViewer::setTargetAltitude_ft (double alt_ft)
+{
+  _dirty = true;
+  _target_alt_ft = alt_ft;
+}
+
+void
+FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+  _dirty = true;
+  _target_lon_deg = lon_deg;
+  _target_lat_deg = lat_deg;
+  _target_alt_ft = alt_ft;
+}
+
+void
+FGViewer::setRoll_deg (double roll_deg)
+{
+  _dirty = true;
+  _roll_deg = roll_deg;
+}
+
+void
+FGViewer::setPitch_deg (double pitch_deg)
+{
+  _dirty = true;
+  _pitch_deg = pitch_deg;
+}
+
+void
+FGViewer::setHeading_deg (double heading_deg)
+{
+  _dirty = true;
+  _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
+{
+  _dirty = true;
+  _roll_deg = roll_deg;
+  _pitch_deg = pitch_deg;
+  _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setXOffset_m (double x_offset_m)
+{
+  _dirty = true;
+  _x_offset_m = x_offset_m;
+}
+
+void
+FGViewer::setYOffset_m (double y_offset_m)
+{
+  _dirty = true;
+  _y_offset_m = y_offset_m;
+}
+
+void
+FGViewer::setZOffset_m (double z_offset_m)
+{
+  _dirty = true;
+  _z_offset_m = z_offset_m;
+}
+
+void
+FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
+{
+  _dirty = true;
+  _x_offset_m = x_offset_m;
+  _y_offset_m = y_offset_m;
+  _z_offset_m = z_offset_m;
+}
+
+void
+FGViewer::setRollOffset_deg (double roll_offset_deg)
+{
+  _dirty = true;
+  _roll_offset_deg = roll_offset_deg;
+}
+
+void
+FGViewer::setPitchOffset_deg (double pitch_offset_deg)
+{
+  _dirty = true;
+  _pitch_offset_deg = pitch_offset_deg;
+}
+
+void
+FGViewer::setHeadingOffset_deg (double heading_offset_deg)
+{
+  _dirty = true;
+  _heading_offset_deg = heading_offset_deg;
+}
+
+void
+FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
+{
+  _dirty = true;
+  _roll_offset_deg = roll_offset_deg;
+  _pitch_offset_deg = pitch_offset_deg;
+  _heading_offset_deg = heading_offset_deg;
+}
+
+double *
+FGViewer::get_absolute_view_pos () 
 {
   if (_dirty)
     recalc();
   return _absolute_view_pos;
 }
 
-const float *
-FGViewPoint::getRelativeViewPos () const
+float *
+FGViewer::getRelativeViewPos () 
 {
   if (_dirty)
     recalc();
   return _relative_view_pos;
 }
 
-const float *
-FGViewPoint::getZeroElevViewPos () const
+float *
+FGViewer::getZeroElevViewPos () 
 {
   if (_dirty)
     recalc();
   return _zero_elev_view_pos;
 }
 
+
+// recalc() is done every time one of the setters is called (making the 
+// cached data "dirty").  It calculates all the outputs for viewer.
+void
+FGViewer::recalc ()
+{
+  sgVec3 minus_z, right, forward, tilt;
+  sgMat4 VIEWo;
+  sgMat4 tmpROT;  // temp rotation work matrices
+  sgVec3 tmpVec3;  // temp work vector (3)
+
+
+  // The position vectors originate from the view point or target location
+  // depending on the type of view.
+
+  if (_type == FG_RPH) {
+    recalcPositionVectors( _lon_deg, _lat_deg, _alt_ft );
+  } else {
+    recalcPositionVectors( _target_lon_deg, _target_lat_deg, _target_alt_ft );
+  }
+
+  sgCopyVec3(zero_elev, _zero_elev_view_pos);
+  sgCopyVec3(view_pos, _relative_view_pos);
+
+  if (_type == FG_LOOKAT) {
+
+    // Make the world up rotation matrix for lookat
+    sgMakeRotMat4( UP, _target_lon_deg, 0.0, -_target_lat_deg );
+
+    // get the world up verctor from the worldup rotation matrix
+    sgSetVec3( world_up, UP[0][0], UP[0][1], UP[0][2] );
+
+    sgCopyVec3( view_up, world_up );
+    
+
+    // create offset vector
+    sgVec3 lookat_offset;
+    sgSetVec3( lookat_offset, _x_offset_m, _y_offset_m, _z_offset_m );
+
+    // Apply heading orientation and orientation offset to lookat_offset...
+    sgMakeRotMat4( tmpROT, _heading_offset_deg -_heading_deg, world_up);
+    sgXformVec3( lookat_offset, lookat_offset, UP );
+    sgXformVec3( lookat_offset, lookat_offset, tmpROT );
+
+    // Apply orientation offset tilt...
+    // FIXME: Need to get and use a "right" vector instead of 1-0-0
+    sgSetVec3 (tmpVec3, 1, 0, 0);
+    sgMakeRotMat4( tmpROT, _pitch_offset_deg, tmpVec3 );
+    sgXformPnt3( lookat_offset, lookat_offset, tmpROT );
+
+    // add the offsets including rotations to the coordinates
+    sgAddVec3( view_pos, lookat_offset );
+
+    // Make the VIEW matrix.
+    fgMakeLookAtMat4( VIEW, view_pos, view_forward, view_up );
+
+
+    // the VIEW matrix includes both rotation and translation.  Let's
+    // knock out the translation part to make the VIEW_ROT matrix
+    sgCopyMat4( VIEW_ROT, VIEW );
+    VIEW_ROT[3][0] = VIEW_ROT[3][1] = VIEW_ROT[3][2] = 0.0;
+
+  }
+
+  if (_type == FG_RPH) {
+
+    // code to calculate LOCAL matrix calculated from Phi, Theta, and
+    // Psi (roll, pitch, yaw) in case we aren't running LaRCsim as our
+    // flight model
+       
+    fgMakeLOCAL( LOCAL, _pitch_deg * SG_DEGREES_TO_RADIANS,
+                        _roll_deg * SG_DEGREES_TO_RADIANS,
+                        -_heading_deg * SG_DEGREES_TO_RADIANS);
+       
+    // Make the world up rotation matrix for pilot view
+    sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );
+
+    // get the world up verctor from the worldup rotation matrix
+    sgSetVec3( world_up, UP[0][0], UP[0][1], UP[0][2] );
+
+    // VIEWo becomes the rotation matrix with world_up incorporated
+    sgCopyMat4( VIEWo, LOCAL );
+    sgPostMultMat4( VIEWo, UP );
+
+    // generate the sg view up and forward vectors
+    sgSetVec3( view_up, VIEWo[0][0], VIEWo[0][1], VIEWo[0][2] );
+    sgSetVec3( right, VIEWo[1][0], VIEWo[1][1], VIEWo[1][2] );
+    sgSetVec3( forward, VIEWo[2][0], VIEWo[2][1], VIEWo[2][2] );
+
+    // apply the offsets in world coordinates
+    sgVec3 pilot_offset_world;
+    sgSetVec3( pilot_offset_world, 
+              _z_offset_m, _y_offset_m, -_x_offset_m );
+    sgXformVec3( pilot_offset_world, pilot_offset_world, VIEWo );
+
+    // generate the view offset matrix using orientation offset (heading)
+    sgMakeRotMat4( VIEW_OFFSET, _heading_offset_deg, view_up );
+
+    // create a tilt matrix using orientation offset (pitch)
+    sgMat4 VIEW_TILT;
+    sgMakeRotMat4( VIEW_TILT, _pitch_offset_deg, right );
+    sgPreMultMat4(VIEW_OFFSET, VIEW_TILT);
+    sgXformVec3( view_forward, forward, VIEW_OFFSET );
+    SG_LOG( SG_VIEW, SG_DEBUG, "(RPH) view forward = "
+           << view_forward[0] << "," << view_forward[1] << ","
+           << view_forward[2] );
+       
+    // VIEW_ROT = LARC_TO_SSG * ( VIEWo * VIEW_OFFSET )
+    fgMakeViewRot( VIEW_ROT, VIEW_OFFSET, VIEWo );
+
+    sgVec3 trans_vec;
+    sgAddVec3( trans_vec, view_pos, pilot_offset_world );
+
+    // VIEW = VIEW_ROT * TRANS
+    sgCopyMat4( VIEW, VIEW_ROT );
+    sgPostMultMat4ByTransMat4( VIEW, trans_vec );
+
+  }
+
+  // Given a vector pointing straight down (-Z), map into onto the
+  // local plane representing "horizontal".  This should give us the
+  // local direction for moving "south".
+  sgSetVec3( minus_z, 0.0, 0.0, -1.0 );
+
+  sgmap_vec_onto_cur_surface_plane(world_up, view_pos, minus_z,
+                                    surface_south);
+  sgNormalizeVec3(surface_south);
+
+  // now calculate the surface east vector
+  sgVec3 world_down;
+  sgNegateVec3(world_down, world_up);
+  sgVectorProductVec3(surface_east, surface_south, world_down);
+
+  set_clean();
+}
+
 void
-FGViewPoint::recalc () const
+FGViewer::recalcPositionVectors (double lon_deg, double lat_deg, double alt_ft) const
 {
   double sea_level_radius_m;
   double lat_geoc_rad;
 
+
                                // Convert from geodetic to geocentric
                                // coordinates.
-  sgGeodToGeoc(_lat_deg * SGD_DEGREES_TO_RADIANS,
-              _alt_ft * SG_FEET_TO_METER,
+  sgGeodToGeoc(lat_deg * SGD_DEGREES_TO_RADIANS,
+              alt_ft * SG_FEET_TO_METER,
               &sea_level_radius_m,
               &lat_geoc_rad);
 
                                // Calculate the cartesian coordinates
                                // of point directly below at sea level.
-  Point3D p = Point3D(_lon_deg * SG_DEGREES_TO_RADIANS,
+                                // aka Zero Elevation Position
+  Point3D p = Point3D(lon_deg * SG_DEGREES_TO_RADIANS,
                      lat_geoc_rad,
                      sea_level_radius_m);
   Point3D tmp = sgPolarToCart3d(p) - scenery.get_next_center();
@@ -112,12 +449,14 @@ FGViewPoint::recalc () const
 
                                // Calculate the absolute view position
                                // in fgfs coordinates.
-  p.setz(p.radius() + _alt_ft * SG_FEET_TO_METER);
+                                // aka Absolute View Position
+  p.setz(p.radius() + alt_ft * SG_FEET_TO_METER);
   tmp = sgPolarToCart3d(p);
   sgdSetVec3(_absolute_view_pos, tmp[0], tmp[1], tmp[2]);
 
                                // Calculate the relative view position
                                // from the scenery center.
+                                // aka Relative View Position
   sgdVec3 scenery_center;
   sgdSetVec3(scenery_center,
             scenery.get_next_center().x(),
@@ -126,48 +465,7 @@ FGViewPoint::recalc () const
   sgdVec3 view_pos;
   sgdSubVec3(view_pos, _absolute_view_pos, scenery_center);
   sgSetVec3(_relative_view_pos, view_pos);
-}
-
 
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGViewer.
-////////////////////////////////////////////////////////////////////////
-
-// Constructor
-FGViewer::FGViewer( void ):
-    scalingType(FG_SCALING_MAX),
-    fov(55.0),
-    view_offset(0.0),
-    goal_view_offset(0.0),
-    view_tilt(0.0),
-    goal_view_tilt(0.0)
-{
-    sgSetVec3( pilot_offset, 0.0, 0.0, 0.0 );
-    sgdZeroVec3(geod_view_pos);
-    sgdZeroVec3(abs_view_pos);
-    sea_level_radius = SG_EQUATORIAL_RADIUS_M; 
-    //a reasonable guess for init, so that the math doesn't blow up
-}
-
-
-// Destructor
-FGViewer::~FGViewer( void ) {
-}
-
-void
-FGViewer::init ()
-{
-}
-
-void
-FGViewer::bind ()
-{
-}
-
-void
-FGViewer::unbind ()
-{
 }
 
 double
@@ -216,60 +514,164 @@ FGViewer::update (int dt)
 {
   int i;
   for ( i = 0; i < dt; i++ ) {
-    if ( fabs(get_goal_view_offset() - get_view_offset()) < 0.05 ) {
-      set_view_offset( get_goal_view_offset() );
+    if ( fabs(get_goal_view_offset() - getHeadingOffset_deg()) < 1 ) {
+      setHeadingOffset_deg( get_goal_view_offset() );
       break;
     } else {
-      // move current_view.view_offset towards
+      // move current_view.headingoffset towards
       // current_view.goal_view_offset
-      if ( get_goal_view_offset() > get_view_offset() )
+      if ( get_goal_view_offset() > getHeadingOffset_deg() )
        {
-         if ( get_goal_view_offset() - get_view_offset() < SGD_PI ){
-           inc_view_offset( 0.01 );
+         if ( get_goal_view_offset() - getHeadingOffset_deg() < 180 ){
+           inc_view_offset( 0.5 );
          } else {
-           inc_view_offset( -0.01 );
+           inc_view_offset( -0.5 );
          }
        } else {
-         if ( get_view_offset() - get_goal_view_offset() < SGD_PI ){
-           inc_view_offset( -0.01 );
+         if ( getHeadingOffset_deg() - get_goal_view_offset() < 180 ){
+           inc_view_offset( -0.5 );
          } else {
-           inc_view_offset( 0.01 );
+           inc_view_offset( 0.5 );
          }
        }
-      if ( get_view_offset() > SGD_2PI ) {
-       inc_view_offset( -SGD_2PI );
-      } else if ( get_view_offset() < 0 ) {
-       inc_view_offset( SGD_2PI );
+      if ( getHeadingOffset_deg() > 360 ) {
+       inc_view_offset( -360 );
+      } else if ( getHeadingOffset_deg() < 0 ) {
+       inc_view_offset( 360 );
       }
     }
   }
 
   for ( i = 0; i < dt; i++ ) {
-    if ( fabs(get_goal_view_tilt() - get_view_tilt()) < 0.05 ) {
-      set_view_tilt( get_goal_view_tilt() );
+    if ( fabs(get_goal_view_tilt() - getPitchOffset_deg()) < 1 ) {
+      setPitchOffset_deg( get_goal_view_tilt() );
       break;
     } else {
-      // move current_view.view_tilt towards
+      // move current_view.pitch_offset_deg towards
       // current_view.goal_view_tilt
-      if ( get_goal_view_tilt() > get_view_tilt() )
+      if ( get_goal_view_tilt() > getPitchOffset_deg() )
        {
-         if ( get_goal_view_tilt() - get_view_tilt() < SGD_PI ){
-           inc_view_tilt( 0.01 );
+         if ( get_goal_view_tilt() - getPitchOffset_deg() < 0 ){
+           inc_view_tilt( 1.0 );
          } else {
-           inc_view_tilt( -0.01 );
+           inc_view_tilt( -1.0 );
          }
        } else {
-         if ( get_view_tilt() - get_goal_view_tilt() < SGD_PI ){
-           inc_view_tilt( -0.01 );
+         if ( getPitchOffset_deg() - get_goal_view_tilt() < 0 ){
+           inc_view_tilt( -1.0 );
          } else {
-           inc_view_tilt( 0.01 );
+           inc_view_tilt( 1.0 );
          }
        }
-      if ( get_view_tilt() > SGD_2PI ) {
-       inc_view_tilt( -SGD_2PI );
-      } else if ( get_view_tilt() < 0 ) {
-       inc_view_tilt( SGD_2PI );
+      if ( getPitchOffset_deg() > 90 ) {
+       setPitchOffset_deg(90);
+      } else if ( getPitchOffset_deg() < -90 ) {
+       setPitchOffset_deg( -90 );
       }
     }
   }
 }
+
+
+void FGViewer::fgMakeLookAtMat4 ( sgMat4 dst, const sgVec3 eye, const sgVec3 center,
+                       const sgVec3 up )
+{
+  // Caveats:
+  // 1) In order to compute the line of sight, the eye point must not be equal
+  //    to the center point.
+  // 2) The up vector must not be parallel to the line of sight from the eye
+  //    to the center point.
+
+  /* Compute the direction vectors */
+  sgVec3 x,y,z;
+
+  /* Y vector = center - eye */
+  sgSubVec3 ( y, center, eye ) ;
+
+  /* Z vector = up */
+  sgCopyVec3 ( z, up ) ;
+
+  /* X vector = Y cross Z */
+  sgVectorProductVec3 ( x, y, z ) ;
+
+  /* Recompute Z = X cross Y */
+  sgVectorProductVec3 ( z, x, y ) ;
+
+  /* Normalize everything */
+  sgNormaliseVec3 ( x ) ;
+  sgNormaliseVec3 ( y ) ;
+  sgNormaliseVec3 ( z ) ;
+
+  /* Build the matrix */
+#define M(row,col)  dst[row][col]
+  M(0,0) = x[0];    M(0,1) = x[1];    M(0,2) = x[2];    M(0,3) = 0.0;
+  M(1,0) = y[0];    M(1,1) = y[1];    M(1,2) = y[2];    M(1,3) = 0.0;
+  M(2,0) = z[0];    M(2,1) = z[1];    M(2,2) = z[2];    M(2,3) = 0.0;
+  M(3,0) = eye[0];  M(3,1) = eye[1];  M(3,2) = eye[2];  M(3,3) = 1.0;
+#undef M
+}
+/* end from lookat */
+
+/* from rph */
+// VIEW_ROT = LARC_TO_SSG * ( VIEWo * VIEW_OFFSET )
+// This takes advantage of the fact that VIEWo and VIEW_OFFSET
+// only have entries in the upper 3x3 block
+// and that LARC_TO_SSG is just a shift of rows   NHV
+void FGViewer::fgMakeViewRot( sgMat4 dst, const sgMat4 m1, const sgMat4 m2 )
+{
+    for ( int j = 0 ; j < 3 ; j++ ) {
+       dst[2][j] = m2[0][0] * m1[0][j] +
+           m2[0][1] * m1[1][j] +
+           m2[0][2] * m1[2][j];
+
+       dst[0][j] = m2[1][0] * m1[0][j] +
+           m2[1][1] * m1[1][j] +
+           m2[1][2] * m1[2][j];
+
+       dst[1][j] = m2[2][0] * m1[0][j] +
+           m2[2][1] * m1[1][j] +
+           m2[2][2] * m1[2][j];
+    }
+    dst[0][3] = 
+       dst[1][3] = 
+       dst[2][3] = 
+       dst[3][0] = 
+       dst[3][1] = 
+       dst[3][2] = SG_ZERO;
+    dst[3][3] = SG_ONE;
+}
+
+
+void FGViewer::fgMakeLOCAL( sgMat4 dst, const double Theta,
+                               const double Phi, const double Psi)
+{
+    SGfloat cosTheta = (SGfloat) cos(Theta);
+    SGfloat sinTheta = (SGfloat) sin(Theta);
+    SGfloat cosPhi   = (SGfloat) cos(Phi);
+    SGfloat sinPhi   = (SGfloat) sin(Phi);
+    SGfloat sinPsi   = (SGfloat) sin(Psi) ;
+    SGfloat cosPsi   = (SGfloat) cos(Psi) ;
+       
+    dst[0][0] = cosPhi * cosTheta;
+    dst[0][1] =        sinPhi * cosPsi + cosPhi * -sinTheta * -sinPsi;
+    dst[0][2] =        sinPhi * sinPsi + cosPhi * -sinTheta * cosPsi;
+    dst[0][3] =        SG_ZERO;
+
+    dst[1][0] = -sinPhi * cosTheta;
+    dst[1][1] =        cosPhi * cosPsi + -sinPhi * -sinTheta * -sinPsi;
+    dst[1][2] =        cosPhi * sinPsi + -sinPhi * -sinTheta * cosPsi;
+    dst[1][3] = SG_ZERO ;
+       
+    dst[2][0] = sinTheta;
+    dst[2][1] =        cosTheta * -sinPsi;
+    dst[2][2] =        cosTheta * cosPsi;
+    dst[2][3] = SG_ZERO;
+       
+    dst[3][0] = SG_ZERO;
+    dst[3][1] = SG_ZERO;
+    dst[3][2] = SG_ZERO;
+    dst[3][3] = SG_ONE ;
+}
+
+/* end from rph */
+
index 7c1a5e58d27cb39f38f110bd23bbb64f7c015c09..c7bae2d4b40dc818eef0a3c1c8851b44d743bada 100644 (file)
@@ -2,6 +2,8 @@
 //
 // Written by Curtis Olson, started August 1997.
 //                          overhaul started October 2000.
+//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+//                          by David Megginson March 2002
 //
 // Copyright (C) 1997 - 2000  Curtis L. Olson  - curt@flightgear.org
 //
 #define FG_FOV_MAX 179.9
 
 
-/**
- * Representation of a single viewpoint in the FlightGear world.
- */
-class FGViewPoint
-{
+// Define a structure containing view information
+class FGViewer : public FGSubsystem {
+
 public:
-  FGViewPoint ();
-  virtual ~FGViewPoint ();
 
-  /**
-   * Set the geodetic position for the view point.
-   */
-  virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
+    enum fgViewType {
+       FG_RPH = 0,
+       FG_LOOKAT = 1,
+       FG_HPR = 2
+    };
 
+    enum fgScalingType {  // nominal Field Of View actually applies to ...
+       FG_SCALING_WIDTH,       // window width
+       FG_SCALING_MAX,         // max(width, height)
+       // FG_SCALING_G_MEAN,      // geometric_mean(width, height)
+       // FG_SCALING_INDEPENDENT  // whole screen
+    };
 
-  /**
-   * Get the longitude in degrees.
-   */
-  virtual double getLongitude_deg () const { return _lon_deg; }
+    // Constructor
+    FGViewer( void );
 
-  /**
-   * Get the latitude in degrees.
-   */
-  virtual double getLatitude_deg () const { return _lat_deg; }
+    // Destructor
+    virtual ~FGViewer( void );
 
-  /**
-   * Get the altitude in feet ASL.
-   */
-  virtual double getAltitudeASL_ft () const { return _alt_ft; }
+    //////////////////////////////////////////////////////////////////////
+    // Part 1: standard FGSubsystem implementation.
+    //////////////////////////////////////////////////////////////////////
 
-  /**
-   * Get the absolute view position in fgfs coordinates.
-   */
-  virtual const double * getAbsoluteViewPos () const;
+    virtual void init ();
+    virtual void bind ();
+    virtual void unbind ();
+    void update (int dt);
 
 
-  /**
-   * Get the relative view position in fgfs coordinates.
-   *
-   * The position is relative to the scenery centre.
-   */
-  virtual const float * getRelativeViewPos () const;
+    //////////////////////////////////////////////////////////////////////
+    // Part 2: user settings.
+    //////////////////////////////////////////////////////////////////////
 
+    virtual fgViewType getType() const { return _type; }
+    virtual void setType( int type );
+
+                   // Reference geodetic position of view from position...
+    virtual double getLongitude_deg () const { return _lon_deg; }
+    virtual double getLatitude_deg () const { return _lat_deg; }
+    virtual double getAltitudeASL_ft () const { return _alt_ft; }
+                   // Set individual coordinates for the view point position.
+    virtual void setLongitude_deg (double lon_deg);
+    virtual void setLatitude_deg (double lat_deg);
+    virtual void setAltitude_ft (double alt_ft);
+                   // Set the geodetic position for the view point.
+    virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
+
+                   // Reference geodetic target position...
+    virtual double getTargetLongitude_deg () const { return _target_lon_deg; }
+    virtual double getTargetLatitude_deg () const { return _target_lat_deg; }
+    virtual double getTargetAltitudeASL_ft () const { return _target_alt_ft; }
+                   // Set individual coordinates for the Target point position.
+    virtual void setTargetLongitude_deg (double lon_deg);
+    virtual void setTargetLatitude_deg (double lat_deg);
+    virtual void setTargetAltitude_ft (double alt_ft);
+                   // Set the geodetic position for the Target point.
+    virtual void setTargetPosition (double lon_deg, double lat_deg, double alt_ft);
+
+                   // Refence orientation...
+    virtual double getRoll_deg () const { return _roll_deg; }
+    virtual double getPitch_deg () const {return _pitch_deg; }
+    virtual double getHeading_deg () const {return _heading_deg; }
+    virtual void setRoll_deg (double roll_deg);
+    virtual void setPitch_deg (double pitch_deg);
+    virtual void setHeading_deg (double heading_deg);
+    virtual void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
+
+                   // Position offsets from reference
+    virtual double getXOffset_m () const { return _x_offset_m; }
+    virtual double getYOffset_m () const { return _y_offset_m; }
+    virtual double getZOffset_m () const { return _z_offset_m; }
+    virtual void setXOffset_m (double x_offset_m);
+    virtual void setYOffset_m (double y_offset_m);
+    virtual void setZOffset_m (double z_offset_m);
+    virtual void setPositionOffsets (double x_offset_m,
+                                    double y_offset_m,
+                                    double z_offset_m);
+
+                   // Orientation offsets from reference
+    virtual double getRollOffset_deg () const { return _roll_offset_deg; }
+    virtual double getPitchOffset_deg () const { return _pitch_offset_deg; }
+    virtual double getHeadingOffset_deg () const { return _heading_offset_deg; }
+    virtual void setRollOffset_deg (double roll_offset_deg);
+    virtual void setPitchOffset_deg (double pitch_offset_deg);
+    virtual void setHeadingOffset_deg (double heading_offset_deg);
+    virtual void setOrientationOffsets (double roll_offset_deg,
+                                    double heading_offset_deg,
+                                    double pitch_offset_deg);
 
-  /**
-   * Get the absolute zero-elevation view position in fgfs coordinates.
-   */
-  virtual const float * getZeroElevViewPos () const;
 
-private:
 
-  void recalc () const;
+    //////////////////////////////////////////////////////////////////////
+    // Part 3: output vectors and matrices in FlightGear coordinates.
+    //////////////////////////////////////////////////////////////////////
 
-  mutable sgdVec3 _absolute_view_pos;
-  mutable sgVec3 _relative_view_pos;
-  mutable sgVec3 _zero_elev_view_pos;
+    // Vectors and positions...
+
+           // Get zero view_pos
+    virtual float * get_view_pos() {if ( _dirty ) { recalc(); }        return view_pos; }
+           // Get the absolute view position in fgfs coordinates.
+    virtual double * get_absolute_view_pos ();
+           // Get zero elev
+    virtual float * get_zero_elev() {if ( _dirty ) { recalc(); } return zero_elev; }
+           // Get world up vector
+    virtual float *get_world_up() {if ( _dirty ) { recalc(); } return world_up; }
+           // Get the relative (to scenery center) view position in fgfs coordinates.
+    virtual float * getRelativeViewPos ();
+           // Get the absolute zero-elevation view position in fgfs coordinates.
+    virtual float * getZeroElevViewPos ();
+           // Get surface east vector
+    virtual float *get_surface_east() {        if ( _dirty ) { recalc(); } return surface_east; }
+           // Get surface south vector
+    virtual float *get_surface_south() {if ( _dirty ) { recalc(); } return surface_south; }
+
+           // Matrices...
+    virtual const sgVec4 *get_VIEW() { if ( _dirty ) { recalc(); } return VIEW; }
+    virtual const sgVec4 *get_VIEW_ROT() { if ( _dirty ) { recalc(); } return VIEW_ROT; }
+    virtual const sgVec4 *get_UP() { if ( _dirty ) { recalc(); } return UP; }
+           // (future?)
+           // virtual double get_ground_elev() { if ( _dirty ) { recalc(); } return ground_elev; }
 
-  bool _dirty;
-  double _lon_deg;
-  double _lat_deg;
-  double _alt_ft;
 
-};
+private:
 
+    // flag forcing a recalc of derived view parameters
+    bool _dirty;
 
-// Define a structure containing view information
-class FGViewer {
+    void recalc ();
+    void recalcPositionVectors (double lon_deg, double lat_deg, double alt_ft) const;
 
-public:
+    mutable sgdVec3 _absolute_view_pos;
+    mutable sgVec3 _relative_view_pos;
+    mutable sgVec3 _zero_elev_view_pos;
 
-    enum fgViewType {
-       FG_RPH = 0,
-       FG_LOOKAT = 1,
-       FG_HPR = 2
-    };
+    double _lon_deg;
+    double _lat_deg;
+    double _alt_ft;
+    double _target_lon_deg;
+    double _target_lat_deg;
+    double _target_alt_ft;
 
-    enum fgScalingType {  // nominal Field Of View actually applies to ...
-       FG_SCALING_WIDTH,       // window width
-       FG_SCALING_MAX,         // max(width, height)
-       // FG_SCALING_G_MEAN,      // geometric_mean(width, height)
-       // FG_SCALING_INDEPENDENT  // whole screen
-    };
+    double _roll_deg;
+    double _pitch_deg;
+    double _heading_deg;
 
-private:
+    // Position offsets from center of gravity.  The X axis is positive
+    // out the tail, Y is out the right wing, and Z is positive up.
+    // distance in meters
+    double _x_offset_m;
+    double _y_offset_m;
+    double _z_offset_m;
 
-    // flag forcing a recalc of derived view parameters
-    bool dirty;
+    // orientation offsets from reference
+    double _roll_offset_deg;
+    double _pitch_offset_deg;
+    double _heading_offset_deg;
 
 protected:
 
     fgViewType _type;
     fgScalingType scalingType;
 
-    FGViewPoint view_point;
-
     // the nominal field of view (angle, in degrees)
     double fov; 
 
     // ratio of window width and height; height = width * aspect_ratio
     double aspect_ratio;
 
-    // the current view offset angle from forward (rotated about the
-    // view_up vector)
-    double view_offset;
     bool reverse_view_offset;
 
     // the goal view offset angle  (used for smooth view changes)
     double goal_view_offset;
 
-    // the view tilt angles
-    double view_tilt;
     double goal_view_tilt;
 
-    // geodetic view position
-    sgdVec3 geod_view_pos;
-
-    // absolute view position in earth coordinates
-    sgdVec3 abs_view_pos;
-
     // view position in opengl world coordinates (this is the
     // abs_view_pos translated to scenery.center)
     sgVec3 view_pos;
@@ -175,11 +238,6 @@ protected:
     // height ASL of the terrain for our current view position
     // (future?) double ground_elev;
 
-    // pilot offset from center of gravity.  The X axis is positive
-    // out the tail, Y is out the right wing, and Z is positive up.
-    // Distances in meters of course.
-    sgVec3 pilot_offset;
-
     // surface vector heading south
     sgVec3 surface_south;
 
@@ -194,24 +252,35 @@ protected:
     // sg versions of our friendly matrices
     sgMat4 VIEW, VIEW_ROT, UP;
 
-    inline void set_dirty() { dirty = true; }
-    inline void set_clean() { dirty = false; }
+    // up vector for the view (usually point straight up through the
+    // top of the aircraft
+    sgVec3 view_up;
 
-    // Update the view volume, position, and orientation
-    virtual void update() = 0;
+    // the vector pointing straight out the nose of the aircraft
+    sgVec3 view_forward;
 
-public:
+    // Transformation matrix for the view direction offset relative to
+    // the AIRCRAFT matrix
+    sgMat4 VIEW_OFFSET;
 
-    // Constructor
-    FGViewer( void );
+    // sg versions of our friendly matrices (from lookat)
+    sgMat4 LOCAL, TRANS, LARC_TO_SSG;
 
-    // Destructor
-    virtual ~FGViewer( void );
+    inline void set_dirty() { _dirty = true; }
+    inline void set_clean() { _dirty = false; }
+
+    // from lookat
+    void fgMakeLookAtMat4 ( sgMat4 dst, const sgVec3 eye, const sgVec3 center,
+                       const sgVec3 up );
+
+    // from rph
+    void fgMakeViewRot( sgMat4 dst, const sgMat4 m1, const sgMat4 m2 );
+    void fgMakeLOCAL( sgMat4 dst, const double Theta,
+                               const double Phi, const double Psi);
+
+
+public:
 
-    virtual void init ();
-    virtual void bind ();
-    virtual void unbind ();
-    virtual void update (int dt);
 
     //////////////////////////////////////////////////////////////////////
     // setter functions
@@ -224,127 +293,81 @@ public:
     inline void set_aspect_ratio( double r ) {
        aspect_ratio = r;
     }
-    inline void set_view_offset( double a ) {
-       set_dirty();
-       view_offset = a;
-    }
     inline void inc_view_offset( double amt ) {
        set_dirty();
-       view_offset += amt;
+       _heading_offset_deg += amt;
     }
     inline void set_goal_view_offset( double a) {
        set_dirty();
        goal_view_offset = a;
        while ( goal_view_offset < 0.0 ) {
-           goal_view_offset += SGD_2PI;
+           goal_view_offset += 360;
        }
-       while ( goal_view_offset > SGD_2PI ) {
-           goal_view_offset -= SGD_2PI;
+       while ( goal_view_offset > 360 ) {
+           goal_view_offset -= 360;
        }
     }
     inline void set_reverse_view_offset( bool val ) {
        reverse_view_offset = val;
     }
-    inline void set_view_tilt( double a ) {
-       set_dirty();
-       view_tilt = a;
-    }
     inline void inc_view_tilt( double amt ) {
        set_dirty();
-       view_tilt += amt;
+       _pitch_offset_deg += amt;
     }
     inline void set_goal_view_tilt( double a) {
        set_dirty();
        goal_view_tilt = a;
-       while ( goal_view_tilt < 0 ) {
-           goal_view_tilt += 360.0;
+       while ( goal_view_tilt < -90 ) {
+           goal_view_tilt = -90.0;
        }
-       while ( goal_view_tilt > 360.0 ) {
-           goal_view_tilt -= 360.0;
+       while ( goal_view_tilt > 90.0 ) {
+           goal_view_tilt = 90.0;
        }
     }
-    inline void set_geod_view_pos( double lon, double lat, double alt ) {
-       // data should be in radians and meters asl
+    inline void set_sea_level_radius( double r ) {
+       // data should be in meters from the center of the earth
        set_dirty();
-       // cout << "set_geod_view_pos = " << lon << ", " << lat << ", " << alt
-       //      << endl;
-       sgdSetVec3( geod_view_pos, lon, lat, alt );
+       sea_level_radius = r;
     }
-    inline void set_pilot_offset( float x, float y, float z ) {
+
+    /* from lookat */
+    inline void set_view_forward( sgVec3 vf ) {
        set_dirty();
-       sgSetVec3( pilot_offset, x, y, z );
+       sgCopyVec3( view_forward, vf );
     }
-    inline void set_sea_level_radius( double r ) {
-       // data should be in meters from the center of the earth
+    inline void set_view_up( sgVec3 vf ) {
        set_dirty();
-       sea_level_radius = r;
+       sgCopyVec3( view_up, vf );
     }
+    /* end from lookat */
+
 
     //////////////////////////////////////////////////////////////////////
     // accessor functions
     //////////////////////////////////////////////////////////////////////
     inline int get_type() const { return _type ; }
     inline int is_a( int t ) const { return get_type() == t ; }
-    inline bool is_dirty() const { return dirty; }
+    inline bool is_dirty() const { return _dirty; }
     inline double get_fov() const { return fov; }
     inline double get_aspect_ratio() const { return aspect_ratio; }
-    inline double get_view_offset() const { return view_offset; }
     inline bool get_reverse_view_offset() const { return reverse_view_offset; }
     inline double get_goal_view_offset() const { return goal_view_offset; }
-    inline double get_view_tilt() const { return view_tilt; }
     inline double get_goal_view_tilt() const { return goal_view_tilt; }
-    inline double *get_geod_view_pos() { return geod_view_pos; }
-    inline float *get_pilot_offset() { return pilot_offset; }
     inline double get_sea_level_radius() const { return sea_level_radius; }
     // Get horizontal field of view angle, in degrees.
     double get_h_fov();
     // Get vertical field of view angle, in degrees.
     double get_v_fov();
 
+    /* from lookat */
+    inline float *get_view_forward() { return view_forward; }
+    inline float *get_view_up() { return view_up; }
+    /* end from lookat */
+
     //////////////////////////////////////////////////////////////////////
     // derived values accessor functions
     //////////////////////////////////////////////////////////////////////
-    inline double *get_abs_view_pos() {
-       if ( dirty ) { update(); }
-       return abs_view_pos;
-    }
-    inline float *get_view_pos() {
-       if ( dirty ) { update(); }
-       return view_pos;
-    }
-    inline float *get_zero_elev() {
-       if ( dirty ) { update(); }
-       return zero_elev;
-    }
-    // (future?)
-    // inline double get_ground_elev() {
-    //  if ( dirty ) { update(); }
-    // return ground_elev;
-    // }
-    inline float *get_surface_south() {
-       if ( dirty ) { update(); }
-       return surface_south;
-    }
-    inline float *get_surface_east() {
-       if ( dirty ) { update(); }
-       return surface_east;
-    }
-    inline float *get_world_up() {
-       if ( dirty ) { update(); }
-       return world_up;
-    }
-    inline const sgVec4 *get_VIEW() {
-       if ( dirty ) { update(); }
-       return VIEW;
-    }
-    inline const sgVec4 *get_VIEW_ROT() {
-       if ( dirty ) { update(); }
-       return VIEW_ROT;
-    }
-    inline const sgVec4 *get_UP() {
-       if ( dirty ) { update(); }
-       return UP;
-    }
+
 };
 
 
index 43921da9c14286b6c97f1df30ce37f881574e30e..27410d4c49a5991e86d79d9838d7bb3b8ddfa731 100644 (file)
@@ -1,6 +1,7 @@
 // viewmgr.cxx -- class for managing all the views in the flightgear world.
 //
 // Written by Curtis Olson, started October 2000.
+//   partially rewritten by Jim Wilson March 2002
 //
 // Copyright (C) 2000  Curtis L. Olson  - curt@flightgear.org
 //
@@ -44,8 +45,8 @@ FGViewMgr::~FGViewMgr( void ) {
 void
 FGViewMgr::init ()
 {
-  add_view(new FGViewerRPH);
-  add_view(new FGViewerLookAt);
+  add_view(new FGViewer, 0);
+  add_view(new FGViewer, 1);
 }
 
 typedef double (FGViewMgr::*double_getter)() const;
@@ -120,38 +121,44 @@ FGViewMgr::update (int dt)
     * SGD_DEGREES_TO_RADIANS;
 
                                // Set up the pilot view
-  FGViewerRPH *pilot_view = (FGViewerRPH *)get_view( 0 );
-  pilot_view ->set_geod_view_pos(lon_rad, lat_rad, alt_m);
-  pilot_view->set_rph(roll_rad, pitch_rad, heading_rad);
+  FGViewer *pilot_view = (FGViewer *)get_view( 0 );
+  pilot_view ->setPosition(
+       fgGetDouble("/position/longitude-deg"),
+       fgGetDouble("/position/latitude-deg"),
+       fgGetDouble("/position/altitude-ft"));
+  pilot_view->setOrientation(
+       fgGetDouble("/orientation/roll-deg"),
+       fgGetDouble("/orientation/pitch-deg"),
+       fgGetDouble("/orientation/heading-deg"));
   if (fgGetString("/sim/flight-model") == "ada") {
     //+ve x is aft, +ve z is up (see viewer.hxx)
-    pilot_view->set_pilot_offset( -5.0, 0.0, 1.0 ); 
+    pilot_view->setPositionOffsets( -5.0, 0.0, 1.0 );
   }
 
                                // Set up the chase view
 
-                               // FIXME: the matrix math belongs in
-                               // the viewer, not here.
-  FGViewerLookAt *chase_view = (FGViewerLookAt *)get_view( 1 );
-
-  sgVec3 po;           // chase view pilot_offset
-  sgVec3 wup;          // chase view world up
-  sgSetVec3( po, 0.0, 0.0, 100.0 );
-  sgCopyVec3( wup, pilot_view->get_world_up() );
-  sgMat4 CXFM;         // chase view + pilot offset xform
-  sgMakeRotMat4( CXFM,
-                chase_view->get_view_offset() * SGD_RADIANS_TO_DEGREES -
-                heading_rad * SGD_RADIANS_TO_DEGREES,
-                wup );
-  sgVec3 npo;          // new pilot offset after rotation
-  sgVec3 *pPO = PilotOffsetGet();
-  sgXformVec3( po, *pPO, pilot_view->get_UP() );
-  sgXformVec3( npo, po, CXFM );
+  FGViewer *chase_view = (FGViewer *)get_view( 1 );
 
-  chase_view->set_geod_view_pos(lon_rad, lat_rad, alt_m);
-  chase_view->set_pilot_offset( npo[0], npo[1], npo[2] );
-  chase_view->set_view_forward( pilot_view->get_view_pos() ); 
-  chase_view->set_view_up( wup );
+  // get xyz Position offsets directly from GUI/sgVec3Slider
+  // FIXME: change GUI/sgVec3Slider to store the xyz in properties
+  // it would probably be faster than the way PilotOffsetGet()
+  // triggers a recalc all the time.
+  sgVec3 *pPO = PilotOffsetGet();
+  sgVec3 zPO;
+  sgCopyVec3( zPO, *pPO );
+  chase_view->setPositionOffsets(zPO[0], zPO[1], zPO[2] );
+
+  chase_view->setOrientation(
+       fgGetDouble("/orientation/roll-deg"),
+       fgGetDouble("/orientation/pitch-deg"),
+       fgGetDouble("/orientation/heading-deg"));
+
+  chase_view ->setTargetPosition(
+       fgGetDouble("/position/longitude-deg"),
+       fgGetDouble("/position/latitude-deg"),
+       fgGetDouble("/position/altitude-ft"));
+  chase_view->setPositionOffsets(zPO[0], zPO[1], zPO[2] );
+  chase_view->set_view_forward( pilot_view->get_view_pos() );
 
                                // Update the current view
   do_axes();
@@ -162,7 +169,7 @@ double
 FGViewMgr::getViewOffset_deg () const
 {
   const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_view_offset() * SGD_RADIANS_TO_DEGREES);
+  return (view == 0 ? 0 : view->getHeadingOffset_deg());
 }
 
 void
@@ -170,14 +177,14 @@ FGViewMgr::setViewOffset_deg (double offset)
 {
   FGViewer * view = get_current_view();
   if (view != 0)
-    view->set_view_offset(offset * SGD_DEGREES_TO_RADIANS);
+    view->setHeadingOffset_deg(offset);
 }
 
 double
 FGViewMgr::getGoalViewOffset_deg () const
 {
   const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_goal_view_offset() * SGD_RADIANS_TO_DEGREES);
+  return (view == 0 ? 0 : view->get_goal_view_offset());
 }
 
 void
@@ -185,14 +192,14 @@ FGViewMgr::setGoalViewOffset_deg (double offset)
 {
   FGViewer * view = get_current_view();
   if (view != 0)
-    view->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS);
+    view->set_goal_view_offset(offset);
 }
 
 double
 FGViewMgr::getViewTilt_deg () const
 {
   const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_view_tilt() * SGD_RADIANS_TO_DEGREES);
+  return (view == 0 ? 0 : view->getPitchOffset_deg());
 }
 
 void
@@ -200,14 +207,14 @@ FGViewMgr::setViewTilt_deg (double tilt)
 {
   FGViewer * view = get_current_view();
   if (view != 0)
-    view->set_view_tilt(tilt * SGD_DEGREES_TO_RADIANS);
+    view->setPitchOffset_deg(tilt);
 }
 
 double
 FGViewMgr::getGoalViewTilt_deg () const
 {
   const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_goal_view_tilt() * SGD_RADIANS_TO_DEGREES);
+  return (view == 0 ? 0 : view->get_goal_view_tilt());
 }
 
 void
@@ -215,7 +222,7 @@ FGViewMgr::setGoalViewTilt_deg (double tilt)
 {
   FGViewer * view = get_current_view();
   if (view != 0)
-    view->set_goal_view_tilt(tilt * SGD_DEGREES_TO_RADIANS);
+    view->set_goal_view_tilt(tilt);
 }
 
 double
@@ -224,8 +231,7 @@ FGViewMgr::getPilotXOffset_m () const
                                // FIXME: hard-coded pilot view position
   const FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = ((FGViewer *)pilot_view)->get_pilot_offset();
-    return offset[0];
+    return ((FGViewer *)pilot_view)->getXOffset_m();
   } else {
     return 0;
   }
@@ -237,8 +243,7 @@ FGViewMgr::setPilotXOffset_m (double x)
                                // FIXME: hard-coded pilot view position
   FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = pilot_view->get_pilot_offset();
-    pilot_view->set_pilot_offset(x, offset[1], offset[2]);
+    pilot_view->setXOffset_m(x);
   }
 }
 
@@ -248,8 +253,7 @@ FGViewMgr::getPilotYOffset_m () const
                                // FIXME: hard-coded pilot view position
   const FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = ((FGViewer *)pilot_view)->get_pilot_offset();
-    return offset[1];
+    return ((FGViewer *)pilot_view)->getYOffset_m();
   } else {
     return 0;
   }
@@ -261,8 +265,7 @@ FGViewMgr::setPilotYOffset_m (double y)
                                // FIXME: hard-coded pilot view position
   FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = pilot_view->get_pilot_offset();
-    pilot_view->set_pilot_offset(offset[0], y, offset[2]);
+    pilot_view->setYOffset_m(y);
   }
 }
 
@@ -272,8 +275,7 @@ FGViewMgr::getPilotZOffset_m () const
                                // FIXME: hard-coded pilot view position
   const FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = ((FGViewer *)pilot_view)->get_pilot_offset();
-    return offset[2];
+    return ((FGViewer *)pilot_view)->getZOffset_m();
   } else {
     return 0;
   }
@@ -285,8 +287,7 @@ FGViewMgr::setPilotZOffset_m (double z)
                                // FIXME: hard-coded pilot view position
   FGViewer * pilot_view = get_view(0);
   if (pilot_view != 0) {
-    float * offset = pilot_view->get_pilot_offset();
-    pilot_view->set_pilot_offset(offset[0], offset[1], z);
+    pilot_view->setZOffset_m(z);
   }
 }
 
@@ -358,5 +359,6 @@ FGViewMgr::do_axes ()
     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
   if ( viewDir < -1 ) viewDir += 360;
 
-  get_current_view()->set_goal_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
+  get_current_view()->set_goal_view_offset(viewDir);
 }
+
index 6e9b76298a9e02bee181dfaabec203af0951bc43..fec031cf574d1080e8a18a2bdccfd2b7fd5a525c 100644 (file)
@@ -39,8 +39,7 @@
 #include <vector>
 
 #include "fgfs.hxx"
-#include "viewer_lookat.hxx"
-#include "viewer_rph.hxx"
+#include "viewer.hxx"
 
 SG_USING_STD(vector);
 
@@ -107,8 +106,10 @@ public:
     // setters
     inline void clear() { views.clear(); }
     inline void set_view( const int v ) { current = v; }
-    inline void add_view( FGViewer * v ) {
+    inline void add_view( FGViewer * v, int type ) {
        views.push_back(v);
+        v->setType(type);
+        v->init();
     }
 
 private:
@@ -146,3 +147,7 @@ private:
 
 
 #endif // _VIEWMGR_HXX
+
+
+
+
index d5d07a9b2135a88adc1bc25f12a3819623ac0bd5..4968b08e0fed26da8cf2370edb0bbc8404f85d80 100644 (file)
@@ -133,7 +133,7 @@ bool FGNewCache::make_space() {
            if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
                // calculate approximate distance from view point
                sgdCopyVec3( abs_view_pos,
-                            globals->get_current_view()->get_abs_view_pos() );
+                            globals->get_current_view()->get_absolute_view_pos() );
 
                SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = " 
                        << abs_view_pos[0] << ","
@@ -220,3 +220,4 @@ bool FGNewCache::insert_tile( FGTileEntry *e ) {
         return false;
     }
 }
+
index a4f4285c29588aee90b21fa1dbabd63d55b44d0a..1ef594afc91eda53960aa7c30cea4b7a91aaa7f8 100644 (file)
@@ -403,7 +403,7 @@ int FGTileMgr::update( double lon, double lat ) {
                        scenery.get_center()[0],
                        scenery.get_center()[1],
                        scenery.get_center()[2] );
-           hit = fgCurrentElev(globals->get_current_view()->get_abs_view_pos(),
+           hit = fgCurrentElev(globals->get_current_view()->get_absolute_view_pos(),
                                sc,
                                current_tile->get_terra_transform(),
                                &hit_list,
@@ -452,3 +452,4 @@ void FGTileMgr::prep_ssg_nodes() {
        tile_cache.next();
    }
 }
+
index fa5617d37e21b7094b1334643dffd11d168855e5..0841cfbfb4ca624eb91c92b55eca017c6cdf3531 100644 (file)
@@ -175,17 +175,17 @@ void fgLIGHT::UpdateAdjFog( void ) {
        SG_LOG( SG_EVENT, SG_ALERT, "Psi rotation bad = " << f->get_Psi() );
        exit(-1);
     }
-    if ( globals->get_current_view()->get_view_offset() < -2.0 * SGD_2PI ||
-        globals->get_current_view()->get_view_offset() > 2.0 * SGD_2PI ) {
+    if ( globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS < -2.0 * SGD_2PI ||
+        globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS > 2.0 * SGD_2PI ) {
        SG_LOG( SG_EVENT, SG_ALERT, "current view()->view offset bad = " 
-               << globals->get_current_view()->get_view_offset() );
+               << globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS );
        exit(-1);
     }
 
     // first determine the difference between our view angle and local
     // direction to the sun
     rotation = -(sun_rotation + SGD_PI) 
-       - (f->get_Psi() - globals->get_current_view()->get_view_offset());
+       - (f->get_Psi() - globals->get_current_view()->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS);
     if ( globals->get_current_view()->get_reverse_view_offset() ) {
        rotation += SGD_PI;
     }
@@ -241,3 +241,4 @@ fgLIGHT::~fgLIGHT( void ) {
 }
 
 
+