1
0
Fork 0

Major viewer-code overhaul from Jim Wilson:

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.
This commit is contained in:
david 2002-03-20 17:43:28 +00:00
parent 99fa3a6e79
commit 4d4cd16012
14 changed files with 836 additions and 376 deletions

View file

@ -259,7 +259,7 @@ float get_climb_rate( void )
float get_view_direction( 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) double view = ( current_aircraft.fdm_state->get_Psi() + view_off)
* SGD_RADIANS_TO_DEGREES; * SGD_RADIANS_TO_DEGREES;
@ -745,3 +745,4 @@ void fgCockpitUpdate( void ) {
glViewport( 0, 0, iwidth, iheight ); glViewport( 0, 0, iwidth, iheight );
} }

View file

@ -89,7 +89,7 @@ fgPanelVisible ()
return false; return false;
if(globals->get_viewmgr()->get_current() != 0) if(globals->get_viewmgr()->get_current() != 0)
return false; 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")) !fgGetBool("/sim/virtual-cockpit"))
return false; return false;
return true; return true;
@ -452,8 +452,8 @@ FGPanel::setupVirtualCockpit()
// Generate a "look at" matrix using OpenGL (!) coordinate // Generate a "look at" matrix using OpenGL (!) coordinate
// conventions. // conventions.
float lookat[3]; float lookat[3];
float pitch = view->get_view_tilt(); float pitch = view->getPitchOffset_deg() * SGD_DEGREES_TO_RADIANS;
float rot = view->get_view_offset(); float rot = view->getHeadingOffset_deg() * SGD_DEGREES_TO_RADIANS;
lookat[0] = -sin(rot); lookat[0] = -sin(rot);
lookat[1] = sin(pitch) / cos(pitch); lookat[1] = sin(pitch) / cos(pitch);
lookat[2] = -cos(rot); lookat[2] = -cos(rot);
@ -1150,3 +1150,4 @@ FGSwitchLayer::draw ()
// end of panel.cxx // end of panel.cxx

View file

@ -175,20 +175,30 @@ static inline int right_button( void ) {
static inline void set_goal_view_offset( float offset ) 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 ) 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() { 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() { 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) { static inline void move_brake(float offset) {
@ -476,8 +486,10 @@ void guiMotionFunc ( int x, int y )
offset -= SGD_2PI; offset -= SGD_2PI;
} }
set_goal_view_offset(offset); set_goal_view_offset(offset);
set_goal_view_tilt(asin( GuiQuat_mat[1][2]) * SGD_RADIANS_TO_DEGREES );
#ifdef NO_SMOOTH_MOUSE_VIEW #ifdef NO_SMOOTH_MOUSE_VIEW
set_view_offset(offset); set_view_offset(offset);
set_view_tilt(asin( GuiQuat_mat[1][2]) * SGD_RADIANS_TO_DEGREES );
#endif #endif
break; break;
@ -532,6 +544,7 @@ void guiMouseFunc(int button, int updown, int x, int y)
y = _Vy; y = _Vy;
sgCopyVec4(curGuiQuat, _quat); sgCopyVec4(curGuiQuat, _quat);
set_goal_view_offset(_view_offset); set_goal_view_offset(_view_offset);
set_goal_view_tilt(0.0);
#ifdef NO_SMOOTH_MOUSE_VIEW #ifdef NO_SMOOTH_MOUSE_VIEW
set_view_offset(_view_offset); set_view_offset(_view_offset);
#endif #endif
@ -547,8 +560,10 @@ void guiMouseFunc(int button, int updown, int x, int y)
Quat0(); Quat0();
_view_offset = get_goal_view_offset(); _view_offset = get_goal_view_offset();
set_goal_view_offset(0.0); set_goal_view_offset(0.0);
set_goal_view_tilt(0.0);
#ifdef NO_SMOOTH_MOUSE_VIEW #ifdef NO_SMOOTH_MOUSE_VIEW
set_view_offset(0.0); set_view_offset(0.0);
set_view_tilt(0.0);
#endif #endif
} }
glutWarpPointer( x , y); glutWarpPointer( x , y);
@ -605,8 +620,10 @@ void guiMouseFunc(int button, int updown, int x, int y)
Quat0(); Quat0();
build_rotmatrix(GuiQuat_mat, curGuiQuat); build_rotmatrix(GuiQuat_mat, curGuiQuat);
set_goal_view_offset(0.0); set_goal_view_offset(0.0);
set_goal_view_tilt(0.0);
#ifdef NO_SMOOTH_MOUSE_VIEW #ifdef NO_SMOOTH_MOUSE_VIEW
set_view_offset(0.0); set_view_offset(0.0);
set_view_tilt(0.0);
#endif // NO_SMOOTH_MOUSE_VIEW #endif // NO_SMOOTH_MOUSE_VIEW
#endif // RESET_VIEW_ON_LEAVING_MOUSE_VIEW #endif // RESET_VIEW_ON_LEAVING_MOUSE_VIEW
glutSetCursor(GLUT_CURSOR_INHERIT); glutSetCursor(GLUT_CURSOR_INHERIT);
@ -646,3 +663,5 @@ void guiMouseFunc(int button, int updown, int x, int y)
glutPostRedisplay (); glutPostRedisplay ();
} }

View file

@ -52,8 +52,6 @@ fgfs_SOURCES = \
options.cxx options.hxx \ options.cxx options.hxx \
splash.cxx splash.hxx \ splash.cxx splash.hxx \
viewer.cxx viewer.hxx \ viewer.cxx viewer.hxx \
viewer_lookat.cxx viewer_lookat.hxx \
viewer_rph.cxx viewer_rph.hxx \
viewmgr.cxx viewmgr.hxx viewmgr.cxx viewmgr.hxx
fgfs_LDADD = \ fgfs_LDADD = \
@ -95,3 +93,4 @@ INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src
else else
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
endif endif

View file

@ -242,7 +242,7 @@ do_preferences_load (const SGPropertyNode * arg, SGCommandState ** state)
static bool static bool
do_view_cycle (const SGPropertyNode * arg, SGCommandState ** state) 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(); globals->get_viewmgr()->next_view();
if ( fgGetString("/sim/flight-model") == "ada" ) { if ( fgGetString("/sim/flight-model") == "ada" ) {
globals->get_props()->setBoolValue( "/sim/hud/visibility", true ); globals->get_props()->setBoolValue( "/sim/hud/visibility", true );
@ -605,3 +605,4 @@ fgInitCommands ()
} }
// end of fg_commands.hxx // end of fg_commands.hxx

View file

@ -159,8 +159,8 @@ FGAircraftModel::update (int dt)
do_animation(_animations[i], elapsed_ms); do_animation(_animations[i], elapsed_ms);
_selector->select(true); _selector->select(true);
FGViewerRPH *pilot_view = FGViewer *pilot_view =
(FGViewerRPH *)globals->get_viewmgr()->get_view( 0 ); (FGViewer *)globals->get_viewmgr()->get_view( 0 );
sgMat4 sgTRANS; sgMat4 sgTRANS;
sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() ); sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
@ -178,15 +178,13 @@ FGAircraftModel::update (int dt)
if (view_number == 0) { if (view_number == 0) {
// FIXME: orientation is not applied // FIXME: orientation is not applied
// correctly when view is not forward // correctly when view is not forward
sgMakeRotMat4( sgROT, -pilot_view->get_view_offset() sgMakeRotMat4( sgROT, -pilot_view->getHeadingOffset_deg(),
* SGD_RADIANS_TO_DEGREES, pilot_view->get_world_up() ); pilot_view->get_world_up() );
/* Warning lame hack from Wilson ahead */ /* Warning lame hack from Wilson ahead */
/* get the pitch value */ /* get the pitch value */
sgVec3 rph;
sgCopyVec3(rph, pilot_view->get_rph());
/* double it to counter the value already in the VIEW_ROT */ /* 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 /* make a ROT matrix
with the values waited by the X coordinate from the offset with the values waited by the X coordinate from the offset
rotation see sgROT above rotation see sgROT above
@ -383,3 +381,7 @@ FGAircraftModel::Animation::setRotation()
// end of model.cxx // end of model.cxx

View file

@ -882,11 +882,11 @@ parse_option (const string& arg)
} else { } else {
default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS; default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS;
} }
FGViewerRPH *pilot_view = FGViewer *pilot_view =
(FGViewerRPH *)globals->get_viewmgr()->get_view( 0 ); (FGViewer *)globals->get_viewmgr()->get_view( 0 );
pilot_view->set_view_offset( default_view_offset ); pilot_view->setHeadingOffset_deg( default_view_offset * SGD_RADIANS_TO_DEGREES );
pilot_view->set_goal_view_offset( default_view_offset ); pilot_view->set_goal_view_offset( default_view_offset * SGD_RADIANS_TO_DEGREES );
fgSetDouble("/sim/view/offset-deg", default_view_offset); fgSetDouble("/sim/view/offset-deg", default_view_offset * SGD_RADIANS_TO_DEGREES );
// $$$ end - added VS Renganathan, 14 Oct 2K // $$$ end - added VS Renganathan, 14 Oct 2K
} else if ( arg.find( "--visibility=" ) == 0 ) { } else if ( arg.find( "--visibility=" ) == 0 ) {
fgSetDouble("/environment/visibility-m", atof(arg.substr(13))); fgSetDouble("/environment/visibility-m", atof(arg.substr(13)));
@ -1297,3 +1297,5 @@ fgUsage ()
<< " instances allowed." << endl << " instances allowed." << endl
<< endl; << endl;
} }

View file

@ -2,6 +2,8 @@
// //
// Written by Curtis Olson, started August 1997. // Written by Curtis Olson, started August 1997.
// overhaul started October 2000. // 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 // Copyright (C) 1997 - 2000 Curtis L. Olson - curt@flightgear.org
// //
@ -36,99 +38,13 @@
#include <Scenery/scenery.hxx> #include <Scenery/scenery.hxx>
/* from lookat */
#include <simgear/math/vector.hxx>
#include "globals.hxx"
/* end from lookat */
#include "viewer.hxx" #include "viewer.hxx"
////////////////////////////////////////////////////////////////////////
// Implementation of FGViewPoint.
////////////////////////////////////////////////////////////////////////
FGViewPoint::FGViewPoint ()
: _dirty(true),
_lon_deg(0),
_lat_deg(0),
_alt_ft(0)
{
}
FGViewPoint::~FGViewPoint ()
{
}
void
FGViewPoint::setPosition (double lon_deg, double lat_deg, double alt_ft)
{
_dirty = true;
_lon_deg = lon_deg;
_lat_deg = lat_deg;
_alt_ft = alt_ft;
}
const double *
FGViewPoint::getAbsoluteViewPos () const
{
if (_dirty)
recalc();
return _absolute_view_pos;
}
const float *
FGViewPoint::getRelativeViewPos () const
{
if (_dirty)
recalc();
return _relative_view_pos;
}
const float *
FGViewPoint::getZeroElevViewPos () const
{
if (_dirty)
recalc();
return _zero_elev_view_pos;
}
void
FGViewPoint::recalc () 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,
&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,
lat_geoc_rad,
sea_level_radius_m);
Point3D tmp = sgPolarToCart3d(p) - scenery.get_next_center();
sgSetVec3(_zero_elev_view_pos, tmp[0], tmp[1], tmp[2]);
// Calculate the absolute view position
// in fgfs coordinates.
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.
sgdVec3 scenery_center;
sgdSetVec3(scenery_center,
scenery.get_next_center().x(),
scenery.get_next_center().y(),
scenery.get_next_center().z());
sgdVec3 view_pos;
sgdSubVec3(view_pos, _absolute_view_pos, scenery_center);
sgSetVec3(_relative_view_pos, view_pos);
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Implementation of FGViewer. // Implementation of FGViewer.
@ -138,14 +54,26 @@ FGViewPoint::recalc () const
FGViewer::FGViewer( void ): FGViewer::FGViewer( void ):
scalingType(FG_SCALING_MAX), scalingType(FG_SCALING_MAX),
fov(55.0), fov(55.0),
view_offset(0.0),
goal_view_offset(0.0), goal_view_offset(0.0),
view_tilt(0.0), goal_view_tilt(0.0),
goal_view_tilt(0.0) _dirty(true),
_lon_deg(0),
_lat_deg(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)
{ {
sgSetVec3( pilot_offset, 0.0, 0.0, 0.0 ); sgdZeroVec3(_absolute_view_pos);
sgdZeroVec3(geod_view_pos);
sgdZeroVec3(abs_view_pos);
sea_level_radius = SG_EQUATORIAL_RADIUS_M; sea_level_radius = SG_EQUATORIAL_RADIUS_M;
//a reasonable guess for init, so that the math doesn't blow up //a reasonable guess for init, so that the math doesn't blow up
} }
@ -158,6 +86,13 @@ FGViewer::~FGViewer( void ) {
void void
FGViewer::init () FGViewer::init ()
{ {
if ( _type == FG_LOOKAT ) {
set_reverse_view_offset(true);
}
if ( _type == FG_RPH ) {
set_reverse_view_offset(false);
}
} }
void void
@ -170,6 +105,369 @@ FGViewer::unbind ()
{ {
} }
void
FGViewer::setType ( int type )
{
if (type == 0)
_type = FG_RPH;
if (type == 1)
_type = FG_LOOKAT;
}
void
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;
}
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;
}
float *
FGViewer::getRelativeViewPos ()
{
if (_dirty)
recalc();
return _relative_view_pos;
}
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
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,
&sea_level_radius_m,
&lat_geoc_rad);
// Calculate the cartesian coordinates
// of point directly below at sea level.
// 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();
sgSetVec3(_zero_elev_view_pos, tmp[0], tmp[1], tmp[2]);
// Calculate the absolute view position
// in fgfs coordinates.
// 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(),
scenery.get_next_center().y(),
scenery.get_next_center().z());
sgdVec3 view_pos;
sgdSubVec3(view_pos, _absolute_view_pos, scenery_center);
sgSetVec3(_relative_view_pos, view_pos);
}
double double
FGViewer::get_h_fov() FGViewer::get_h_fov()
{ {
@ -216,60 +514,164 @@ FGViewer::update (int dt)
{ {
int i; int i;
for ( i = 0; i < dt; i++ ) { for ( i = 0; i < dt; i++ ) {
if ( fabs(get_goal_view_offset() - get_view_offset()) < 0.05 ) { if ( fabs(get_goal_view_offset() - getHeadingOffset_deg()) < 1 ) {
set_view_offset( get_goal_view_offset() ); setHeadingOffset_deg( get_goal_view_offset() );
break; break;
} else { } else {
// move current_view.view_offset towards // move current_view.headingoffset towards
// current_view.goal_view_offset // 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 ){ if ( get_goal_view_offset() - getHeadingOffset_deg() < 180 ){
inc_view_offset( 0.01 ); inc_view_offset( 0.5 );
} else { } else {
inc_view_offset( -0.01 ); inc_view_offset( -0.5 );
} }
} else { } else {
if ( get_view_offset() - get_goal_view_offset() < SGD_PI ){ if ( getHeadingOffset_deg() - get_goal_view_offset() < 180 ){
inc_view_offset( -0.01 ); inc_view_offset( -0.5 );
} else { } else {
inc_view_offset( 0.01 ); inc_view_offset( 0.5 );
} }
} }
if ( get_view_offset() > SGD_2PI ) { if ( getHeadingOffset_deg() > 360 ) {
inc_view_offset( -SGD_2PI ); inc_view_offset( -360 );
} else if ( get_view_offset() < 0 ) { } else if ( getHeadingOffset_deg() < 0 ) {
inc_view_offset( SGD_2PI ); inc_view_offset( 360 );
} }
} }
} }
for ( i = 0; i < dt; i++ ) { for ( i = 0; i < dt; i++ ) {
if ( fabs(get_goal_view_tilt() - get_view_tilt()) < 0.05 ) { if ( fabs(get_goal_view_tilt() - getPitchOffset_deg()) < 1 ) {
set_view_tilt( get_goal_view_tilt() ); setPitchOffset_deg( get_goal_view_tilt() );
break; break;
} else { } else {
// move current_view.view_tilt towards // move current_view.pitch_offset_deg towards
// current_view.goal_view_tilt // 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 ){ if ( get_goal_view_tilt() - getPitchOffset_deg() < 0 ){
inc_view_tilt( 0.01 ); inc_view_tilt( 1.0 );
} else { } else {
inc_view_tilt( -0.01 ); inc_view_tilt( -1.0 );
} }
} else { } else {
if ( get_view_tilt() - get_goal_view_tilt() < SGD_PI ){ if ( getPitchOffset_deg() - get_goal_view_tilt() < 0 ){
inc_view_tilt( -0.01 ); inc_view_tilt( -1.0 );
} else { } else {
inc_view_tilt( 0.01 ); inc_view_tilt( 1.0 );
} }
} }
if ( get_view_tilt() > SGD_2PI ) { if ( getPitchOffset_deg() > 90 ) {
inc_view_tilt( -SGD_2PI ); setPitchOffset_deg(90);
} else if ( get_view_tilt() < 0 ) { } else if ( getPitchOffset_deg() < -90 ) {
inc_view_tilt( SGD_2PI ); 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 */

View file

@ -2,6 +2,8 @@
// //
// Written by Curtis Olson, started August 1997. // Written by Curtis Olson, started August 1997.
// overhaul started October 2000. // 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 // Copyright (C) 1997 - 2000 Curtis L. Olson - curt@flightgear.org
// //
@ -42,73 +44,8 @@
#define FG_FOV_MAX 179.9 #define FG_FOV_MAX 179.9
/**
* Representation of a single viewpoint in the FlightGear world.
*/
class FGViewPoint
{
public:
FGViewPoint ();
virtual ~FGViewPoint ();
/**
* Set the geodetic position for the view point.
*/
virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
/**
* Get the longitude in degrees.
*/
virtual double getLongitude_deg () const { return _lon_deg; }
/**
* Get the latitude in degrees.
*/
virtual double getLatitude_deg () const { return _lat_deg; }
/**
* Get the altitude in feet ASL.
*/
virtual double getAltitudeASL_ft () const { return _alt_ft; }
/**
* Get the absolute view position in fgfs coordinates.
*/
virtual const double * getAbsoluteViewPos () const;
/**
* Get the relative view position in fgfs coordinates.
*
* The position is relative to the scenery centre.
*/
virtual const float * getRelativeViewPos () const;
/**
* Get the absolute zero-elevation view position in fgfs coordinates.
*/
virtual const float * getZeroElevViewPos () const;
private:
void recalc () const;
mutable sgdVec3 _absolute_view_pos;
mutable sgVec3 _relative_view_pos;
mutable sgVec3 _zero_elev_view_pos;
bool _dirty;
double _lon_deg;
double _lat_deg;
double _alt_ft;
};
// Define a structure containing view information // Define a structure containing view information
class FGViewer { class FGViewer : public FGSubsystem {
public: public:
@ -125,42 +62,168 @@ public:
// FG_SCALING_INDEPENDENT // whole screen // FG_SCALING_INDEPENDENT // whole screen
}; };
// Constructor
FGViewer( void );
// Destructor
virtual ~FGViewer( void );
//////////////////////////////////////////////////////////////////////
// Part 1: standard FGSubsystem implementation.
//////////////////////////////////////////////////////////////////////
virtual void init ();
virtual void bind ();
virtual void unbind ();
void update (int dt);
//////////////////////////////////////////////////////////////////////
// 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);
//////////////////////////////////////////////////////////////////////
// Part 3: output vectors and matrices in FlightGear coordinates.
//////////////////////////////////////////////////////////////////////
// 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; }
private: private:
// flag forcing a recalc of derived view parameters // flag forcing a recalc of derived view parameters
bool dirty; bool _dirty;
void recalc ();
void recalcPositionVectors (double lon_deg, double lat_deg, double alt_ft) const;
mutable sgdVec3 _absolute_view_pos;
mutable sgVec3 _relative_view_pos;
mutable sgVec3 _zero_elev_view_pos;
double _lon_deg;
double _lat_deg;
double _alt_ft;
double _target_lon_deg;
double _target_lat_deg;
double _target_alt_ft;
double _roll_deg;
double _pitch_deg;
double _heading_deg;
// 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;
// orientation offsets from reference
double _roll_offset_deg;
double _pitch_offset_deg;
double _heading_offset_deg;
protected: protected:
fgViewType _type; fgViewType _type;
fgScalingType scalingType; fgScalingType scalingType;
FGViewPoint view_point;
// the nominal field of view (angle, in degrees) // the nominal field of view (angle, in degrees)
double fov; double fov;
// ratio of window width and height; height = width * aspect_ratio // ratio of window width and height; height = width * aspect_ratio
double 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; bool reverse_view_offset;
// the goal view offset angle (used for smooth view changes) // the goal view offset angle (used for smooth view changes)
double goal_view_offset; double goal_view_offset;
// the view tilt angles
double view_tilt;
double goal_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 // view position in opengl world coordinates (this is the
// abs_view_pos translated to scenery.center) // abs_view_pos translated to scenery.center)
sgVec3 view_pos; sgVec3 view_pos;
@ -175,11 +238,6 @@ protected:
// height ASL of the terrain for our current view position // height ASL of the terrain for our current view position
// (future?) double ground_elev; // (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 // surface vector heading south
sgVec3 surface_south; sgVec3 surface_south;
@ -194,24 +252,35 @@ protected:
// sg versions of our friendly matrices // sg versions of our friendly matrices
sgMat4 VIEW, VIEW_ROT, UP; sgMat4 VIEW, VIEW_ROT, UP;
inline void set_dirty() { dirty = true; } // up vector for the view (usually point straight up through the
inline void set_clean() { dirty = false; } // top of the aircraft
sgVec3 view_up;
// the vector pointing straight out the nose of the aircraft
sgVec3 view_forward;
// Transformation matrix for the view direction offset relative to
// the AIRCRAFT matrix
sgMat4 VIEW_OFFSET;
// sg versions of our friendly matrices (from lookat)
sgMat4 LOCAL, TRANS, LARC_TO_SSG;
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);
// Update the view volume, position, and orientation
virtual void update() = 0;
public: public:
// Constructor
FGViewer( void );
// Destructor
virtual ~FGViewer( void );
virtual void init ();
virtual void bind ();
virtual void unbind ();
virtual void update (int dt);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// setter functions // setter functions
@ -224,127 +293,81 @@ public:
inline void set_aspect_ratio( double r ) { inline void set_aspect_ratio( double r ) {
aspect_ratio = r; aspect_ratio = r;
} }
inline void set_view_offset( double a ) {
set_dirty();
view_offset = a;
}
inline void inc_view_offset( double amt ) { inline void inc_view_offset( double amt ) {
set_dirty(); set_dirty();
view_offset += amt; _heading_offset_deg += amt;
} }
inline void set_goal_view_offset( double a) { inline void set_goal_view_offset( double a) {
set_dirty(); set_dirty();
goal_view_offset = a; goal_view_offset = a;
while ( goal_view_offset < 0.0 ) { while ( goal_view_offset < 0.0 ) {
goal_view_offset += SGD_2PI; goal_view_offset += 360;
} }
while ( goal_view_offset > SGD_2PI ) { while ( goal_view_offset > 360 ) {
goal_view_offset -= SGD_2PI; goal_view_offset -= 360;
} }
} }
inline void set_reverse_view_offset( bool val ) { inline void set_reverse_view_offset( bool val ) {
reverse_view_offset = val; reverse_view_offset = val;
} }
inline void set_view_tilt( double a ) {
set_dirty();
view_tilt = a;
}
inline void inc_view_tilt( double amt ) { inline void inc_view_tilt( double amt ) {
set_dirty(); set_dirty();
view_tilt += amt; _pitch_offset_deg += amt;
} }
inline void set_goal_view_tilt( double a) { inline void set_goal_view_tilt( double a) {
set_dirty(); set_dirty();
goal_view_tilt = a; goal_view_tilt = a;
while ( goal_view_tilt < 0 ) { while ( goal_view_tilt < -90 ) {
goal_view_tilt += 360.0; goal_view_tilt = -90.0;
} }
while ( goal_view_tilt > 360.0 ) { while ( goal_view_tilt > 90.0 ) {
goal_view_tilt -= 360.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
set_dirty();
// cout << "set_geod_view_pos = " << lon << ", " << lat << ", " << alt
// << endl;
sgdSetVec3( geod_view_pos, lon, lat, alt );
}
inline void set_pilot_offset( float x, float y, float z ) {
set_dirty();
sgSetVec3( pilot_offset, x, y, z );
}
inline void set_sea_level_radius( double r ) { inline void set_sea_level_radius( double r ) {
// data should be in meters from the center of the earth // data should be in meters from the center of the earth
set_dirty(); set_dirty();
sea_level_radius = r; sea_level_radius = r;
} }
/* from lookat */
inline void set_view_forward( sgVec3 vf ) {
set_dirty();
sgCopyVec3( view_forward, vf );
}
inline void set_view_up( sgVec3 vf ) {
set_dirty();
sgCopyVec3( view_up, vf );
}
/* end from lookat */
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// accessor functions // accessor functions
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
inline int get_type() const { return _type ; } inline int get_type() const { return _type ; }
inline int is_a( int t ) const { return get_type() == t ; } 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_fov() const { return fov; }
inline double get_aspect_ratio() const { return aspect_ratio; } 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 bool get_reverse_view_offset() const { return reverse_view_offset; }
inline double get_goal_view_offset() const { return goal_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_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; } inline double get_sea_level_radius() const { return sea_level_radius; }
// Get horizontal field of view angle, in degrees. // Get horizontal field of view angle, in degrees.
double get_h_fov(); double get_h_fov();
// Get vertical field of view angle, in degrees. // Get vertical field of view angle, in degrees.
double get_v_fov(); 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 // 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;
}
}; };

View file

@ -1,6 +1,7 @@
// viewmgr.cxx -- class for managing all the views in the flightgear world. // viewmgr.cxx -- class for managing all the views in the flightgear world.
// //
// Written by Curtis Olson, started October 2000. // Written by Curtis Olson, started October 2000.
// partially rewritten by Jim Wilson March 2002
// //
// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org // Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
// //
@ -44,8 +45,8 @@ FGViewMgr::~FGViewMgr( void ) {
void void
FGViewMgr::init () FGViewMgr::init ()
{ {
add_view(new FGViewerRPH); add_view(new FGViewer, 0);
add_view(new FGViewerLookAt); add_view(new FGViewer, 1);
} }
typedef double (FGViewMgr::*double_getter)() const; typedef double (FGViewMgr::*double_getter)() const;
@ -120,38 +121,44 @@ FGViewMgr::update (int dt)
* SGD_DEGREES_TO_RADIANS; * SGD_DEGREES_TO_RADIANS;
// Set up the pilot view // Set up the pilot view
FGViewerRPH *pilot_view = (FGViewerRPH *)get_view( 0 ); FGViewer *pilot_view = (FGViewer *)get_view( 0 );
pilot_view ->set_geod_view_pos(lon_rad, lat_rad, alt_m); pilot_view ->setPosition(
pilot_view->set_rph(roll_rad, pitch_rad, heading_rad); 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") { if (fgGetString("/sim/flight-model") == "ada") {
//+ve x is aft, +ve z is up (see viewer.hxx) //+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 // Set up the chase view
// FIXME: the matrix math belongs in FGViewer *chase_view = (FGViewer *)get_view( 1 );
// the viewer, not here.
FGViewerLookAt *chase_view = (FGViewerLookAt *)get_view( 1 );
sgVec3 po; // chase view pilot_offset // get xyz Position offsets directly from GUI/sgVec3Slider
sgVec3 wup; // chase view world up // FIXME: change GUI/sgVec3Slider to store the xyz in properties
sgSetVec3( po, 0.0, 0.0, 100.0 ); // it would probably be faster than the way PilotOffsetGet()
sgCopyVec3( wup, pilot_view->get_world_up() ); // triggers a recalc all the time.
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(); sgVec3 *pPO = PilotOffsetGet();
sgXformVec3( po, *pPO, pilot_view->get_UP() ); sgVec3 zPO;
sgXformVec3( npo, po, CXFM ); sgCopyVec3( zPO, *pPO );
chase_view->setPositionOffsets(zPO[0], zPO[1], zPO[2] );
chase_view->set_geod_view_pos(lon_rad, lat_rad, alt_m); chase_view->setOrientation(
chase_view->set_pilot_offset( npo[0], npo[1], npo[2] ); fgGetDouble("/orientation/roll-deg"),
chase_view->set_view_forward( pilot_view->get_view_pos() ); fgGetDouble("/orientation/pitch-deg"),
chase_view->set_view_up( wup ); 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 // Update the current view
do_axes(); do_axes();
@ -162,7 +169,7 @@ double
FGViewMgr::getViewOffset_deg () const FGViewMgr::getViewOffset_deg () const
{ {
const FGViewer * view = get_current_view(); 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 void
@ -170,14 +177,14 @@ FGViewMgr::setViewOffset_deg (double offset)
{ {
FGViewer * view = get_current_view(); FGViewer * view = get_current_view();
if (view != 0) if (view != 0)
view->set_view_offset(offset * SGD_DEGREES_TO_RADIANS); view->setHeadingOffset_deg(offset);
} }
double double
FGViewMgr::getGoalViewOffset_deg () const FGViewMgr::getGoalViewOffset_deg () const
{ {
const FGViewer * view = get_current_view(); 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 void
@ -185,14 +192,14 @@ FGViewMgr::setGoalViewOffset_deg (double offset)
{ {
FGViewer * view = get_current_view(); FGViewer * view = get_current_view();
if (view != 0) if (view != 0)
view->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS); view->set_goal_view_offset(offset);
} }
double double
FGViewMgr::getViewTilt_deg () const FGViewMgr::getViewTilt_deg () const
{ {
const FGViewer * view = get_current_view(); 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 void
@ -200,14 +207,14 @@ FGViewMgr::setViewTilt_deg (double tilt)
{ {
FGViewer * view = get_current_view(); FGViewer * view = get_current_view();
if (view != 0) if (view != 0)
view->set_view_tilt(tilt * SGD_DEGREES_TO_RADIANS); view->setPitchOffset_deg(tilt);
} }
double double
FGViewMgr::getGoalViewTilt_deg () const FGViewMgr::getGoalViewTilt_deg () const
{ {
const FGViewer * view = get_current_view(); 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 void
@ -215,7 +222,7 @@ FGViewMgr::setGoalViewTilt_deg (double tilt)
{ {
FGViewer * view = get_current_view(); FGViewer * view = get_current_view();
if (view != 0) if (view != 0)
view->set_goal_view_tilt(tilt * SGD_DEGREES_TO_RADIANS); view->set_goal_view_tilt(tilt);
} }
double double
@ -224,8 +231,7 @@ FGViewMgr::getPilotXOffset_m () const
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
const FGViewer * pilot_view = get_view(0); const FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = ((FGViewer *)pilot_view)->get_pilot_offset(); return ((FGViewer *)pilot_view)->getXOffset_m();
return offset[0];
} else { } else {
return 0; return 0;
} }
@ -237,8 +243,7 @@ FGViewMgr::setPilotXOffset_m (double x)
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
FGViewer * pilot_view = get_view(0); FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = pilot_view->get_pilot_offset(); pilot_view->setXOffset_m(x);
pilot_view->set_pilot_offset(x, offset[1], offset[2]);
} }
} }
@ -248,8 +253,7 @@ FGViewMgr::getPilotYOffset_m () const
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
const FGViewer * pilot_view = get_view(0); const FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = ((FGViewer *)pilot_view)->get_pilot_offset(); return ((FGViewer *)pilot_view)->getYOffset_m();
return offset[1];
} else { } else {
return 0; return 0;
} }
@ -261,8 +265,7 @@ FGViewMgr::setPilotYOffset_m (double y)
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
FGViewer * pilot_view = get_view(0); FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = pilot_view->get_pilot_offset(); pilot_view->setYOffset_m(y);
pilot_view->set_pilot_offset(offset[0], y, offset[2]);
} }
} }
@ -272,8 +275,7 @@ FGViewMgr::getPilotZOffset_m () const
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
const FGViewer * pilot_view = get_view(0); const FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = ((FGViewer *)pilot_view)->get_pilot_offset(); return ((FGViewer *)pilot_view)->getZOffset_m();
return offset[2];
} else { } else {
return 0; return 0;
} }
@ -285,8 +287,7 @@ FGViewMgr::setPilotZOffset_m (double z)
// FIXME: hard-coded pilot view position // FIXME: hard-coded pilot view position
FGViewer * pilot_view = get_view(0); FGViewer * pilot_view = get_view(0);
if (pilot_view != 0) { if (pilot_view != 0) {
float * offset = pilot_view->get_pilot_offset(); pilot_view->setZOffset_m(z);
pilot_view->set_pilot_offset(offset[0], offset[1], z);
} }
} }
@ -358,5 +359,6 @@ FGViewMgr::do_axes ()
viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long ); viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
if ( viewDir < -1 ) viewDir += 360; 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);
} }

View file

@ -39,8 +39,7 @@
#include <vector> #include <vector>
#include "fgfs.hxx" #include "fgfs.hxx"
#include "viewer_lookat.hxx" #include "viewer.hxx"
#include "viewer_rph.hxx"
SG_USING_STD(vector); SG_USING_STD(vector);
@ -107,8 +106,10 @@ public:
// setters // setters
inline void clear() { views.clear(); } inline void clear() { views.clear(); }
inline void set_view( const int v ) { current = v; } 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); views.push_back(v);
v->setType(type);
v->init();
} }
private: private:
@ -146,3 +147,7 @@ private:
#endif // _VIEWMGR_HXX #endif // _VIEWMGR_HXX

View file

@ -133,7 +133,7 @@ bool FGNewCache::make_space() {
if ( e->is_loaded() && (e->get_pending_models() == 0) ) { if ( e->is_loaded() && (e->get_pending_models() == 0) ) {
// calculate approximate distance from view point // calculate approximate distance from view point
sgdCopyVec3( abs_view_pos, 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 = " SG_LOG( SG_TERRAIN, SG_DEBUG, "DIST Abs view pos = "
<< abs_view_pos[0] << "," << abs_view_pos[0] << ","
@ -220,3 +220,4 @@ bool FGNewCache::insert_tile( FGTileEntry *e ) {
return false; return false;
} }
} }

View file

@ -403,7 +403,7 @@ int FGTileMgr::update( double lon, double lat ) {
scenery.get_center()[0], scenery.get_center()[0],
scenery.get_center()[1], scenery.get_center()[1],
scenery.get_center()[2] ); 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, sc,
current_tile->get_terra_transform(), current_tile->get_terra_transform(),
&hit_list, &hit_list,
@ -452,3 +452,4 @@ void FGTileMgr::prep_ssg_nodes() {
tile_cache.next(); tile_cache.next();
} }
} }

View file

@ -175,17 +175,17 @@ void fgLIGHT::UpdateAdjFog( void ) {
SG_LOG( SG_EVENT, SG_ALERT, "Psi rotation bad = " << f->get_Psi() ); SG_LOG( SG_EVENT, SG_ALERT, "Psi rotation bad = " << f->get_Psi() );
exit(-1); exit(-1);
} }
if ( 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()->get_view_offset() > 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 = " 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); exit(-1);
} }
// first determine the difference between our view angle and local // first determine the difference between our view angle and local
// direction to the sun // direction to the sun
rotation = -(sun_rotation + SGD_PI) 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() ) { if ( globals->get_current_view()->get_reverse_view_offset() ) {
rotation += SGD_PI; rotation += SGD_PI;
} }
@ -241,3 +241,4 @@ fgLIGHT::~fgLIGHT( void ) {
} }