- keep class and file names in sync.
#include <cmath>
#include <Main/util.hxx>
#include <Main/globals.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Scenery/scenery.hxx>
#include <simgear/sg_inlines.h>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Scenery/scenery.hxx>
#include <Airports/dynamics.hxx>
#include <Main/globals.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Viewer/viewmgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Time/light.hxx>
#include <GUI/FGFontCache.hxx>
#include <Instrumentation/dclgps.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Viewer/viewmgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <GUI/FGFontCache.hxx>
#include <GUI/gui.h> // for guiErrorMessage
#include <sstream>
#include <simgear/math/SGGeometry.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include "HUD.hxx"
#include "HUD_private.hxx"
#include <FDM/flight.hxx>
#include <Environment/environment.hxx>
#include <Environment/environment_mgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Viewer/viewmgr.hxx>
#include <Airports/airport.hxx>
#include <Airports/xmlloader.hxx>
#include <Network/HTTPClient.hxx>
#include <Viewer/viewmgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Environment/presets.hxx>
#include <Navaids/NavDataCache.hxx>
#include "util.hxx"
#include "main.hxx"
#include "locale.hxx"
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Viewer/viewmgr.hxx>
#include <Environment/presets.hxx>
#include <Network/http/httpd.hxx>
#include <Main/fg_props.hxx>
#include <Viewer/renderer.hxx>
#include <Viewer/viewmgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Scenery/scenery.hxx>
#include <Sound/fg_fx.hxx>
#include <Main/fg_os.hxx>
#include <Cockpit/panel.hxx>
#include <Cockpit/panel_io.hxx>
-#include "Viewer/viewer.hxx"
+#include "Viewer/view.hxx"
#include "Viewer/viewmgr.hxx"
using std::vector;
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Viewer/renderer.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include "light.hxx"
#include "sunsolver.hxx"
renderer.cxx
renderingpipeline.cxx
splash.cxx
- viewer.cxx
+ view.cxx
viewmgr.cxx
)
renderer.hxx
renderingpipeline.hxx
splash.hxx
- viewer.hxx
+ view.hxx
viewmgr.hxx
)
#include <Environment/ephemeris.hxx>
//#include <Main/main.hxx>
-#include "viewer.hxx"
+#include "view.hxx"
#include "viewmgr.hxx"
#include "splash.hxx"
#include "renderer.hxx"
--- /dev/null
+// view.cxx -- class for managing a view in the flightgear world.
+//
+// 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 - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "view.hxx"
+
+#include <simgear/compiler.h>
+#include <cassert>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/constants.h>
+#include <simgear/scene/model/placement.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include "CameraGroup.hxx"
+
+using namespace flightgear;
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGViewer.
+////////////////////////////////////////////////////////////////////////
+
+// Constructor...
+View::View( ViewType Type, bool from_model, int from_model_index,
+ bool at_model, int at_model_index,
+ double damp_roll, double damp_pitch, double damp_heading,
+ double x_offset_m, double y_offset_m, double z_offset_m,
+ double heading_offset_deg, double pitch_offset_deg,
+ double roll_offset_deg,
+ double fov_deg, double aspect_ratio_multiplier,
+ double target_x_offset_m, double target_y_offset_m,
+ double target_z_offset_m, double near_m, bool internal ):
+ _dirty(true),
+ _roll_deg(0),
+ _pitch_deg(0),
+ _heading_deg(0),
+ _target_roll_deg(0),
+ _target_pitch_deg(0),
+ _target_heading_deg(0),
+ _scaling_type(FG_SCALING_MAX)
+{
+ _absolute_view_pos = SGVec3d(0, 0, 0);
+ _type = Type;
+ _from_model = from_model;
+ _from_model_index = from_model_index;
+ _at_model = at_model;
+ _at_model_index = at_model_index;
+
+ _internal = internal;
+
+ _dampFactor = SGVec3d::zeros();
+ _dampOutput = SGVec3d::zeros();
+ _dampTarget = SGVec3d::zeros();
+
+ if (damp_roll > 0.0)
+ _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
+ if (damp_pitch > 0.0)
+ _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
+ if (damp_heading > 0.0)
+ _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
+
+ _offset_m.x() = x_offset_m;
+ _offset_m.y() = y_offset_m;
+ _offset_m.z() = z_offset_m;
+ _configOffset_m = _offset_m;
+
+ _heading_offset_deg = heading_offset_deg;
+ _pitch_offset_deg = pitch_offset_deg;
+ _roll_offset_deg = roll_offset_deg;
+ _goal_heading_offset_deg = heading_offset_deg;
+ _goal_pitch_offset_deg = pitch_offset_deg;
+ _goal_roll_offset_deg = roll_offset_deg;
+
+ _configHeadingOffsetDeg = heading_offset_deg;
+ _configPitchOffsetDeg = pitch_offset_deg;
+ _configRollOffsetDeg = roll_offset_deg;
+
+ if (fov_deg > 0) {
+ _fov_deg = fov_deg;
+ } else {
+ _fov_deg = 55;
+ }
+
+ _configFOV_deg = _fov_deg;
+
+ _aspect_ratio_multiplier = aspect_ratio_multiplier;
+ _target_offset_m.x() = target_x_offset_m;
+ _target_offset_m.y() = target_y_offset_m;
+ _target_offset_m.z() = target_z_offset_m;
+ _configTargetOffset_m = _target_offset_m;
+
+ _ground_level_nearplane_m = near_m;
+ // a reasonable guess for init, so that the math doesn't blow up
+}
+
+View* View::createFromProperties(SGPropertyNode_ptr config)
+{
+ double aspect_ratio_multiplier
+ = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
+
+ // find out if this is an internal view (e.g. in cockpit, low near plane)
+ // FIXME : should be a child of config
+ bool internal = config->getParent()->getBoolValue("internal", false);
+
+
+ // FIXME:
+ // this is assumed to be an aircraft model...we will need to read
+ // model-from-type as well.
+
+ // find out if this is a model we are looking from...
+ bool from_model = config->getBoolValue("from-model");
+ int from_model_index = config->getIntValue("from-model-idx");
+
+ double x_offset_m = config->getDoubleValue("x-offset-m");
+ double y_offset_m = config->getDoubleValue("y-offset-m");
+ double z_offset_m = config->getDoubleValue("z-offset-m");
+
+ double heading_offset_deg = config->getDoubleValue("heading-offset-deg");
+ // config->setDoubleValue("heading-offset-deg", heading_offset_deg);
+ double pitch_offset_deg = config->getDoubleValue("pitch-offset-deg");
+ // config->setDoubleValue("pitch-offset-deg", pitch_offset_deg);
+ double roll_offset_deg = config->getDoubleValue("roll-offset-deg");
+ // config->setDoubleValue("roll-offset-deg", roll_offset_deg);
+
+ double fov_deg = config->getDoubleValue("default-field-of-view-deg");
+ double near_m = config->getDoubleValue("ground-level-nearplane-m");
+
+ View* v = 0;
+ // supporting two types "lookat" = 1 and "lookfrom" = 0
+ const char *type = config->getParent()->getStringValue("type");
+ if (!strcmp(type, "lookat")) {
+ bool at_model = config->getBoolValue("at-model");
+ int at_model_index = config->getIntValue("at-model-idx");
+
+ double damp_roll = config->getDoubleValue("at-model-roll-damping");
+ double damp_pitch = config->getDoubleValue("at-model-pitch-damping");
+ double damp_heading = config->getDoubleValue("at-model-heading-damping");
+
+ double target_x_offset_m = config->getDoubleValue("target-x-offset-m");
+ double target_y_offset_m = config->getDoubleValue("target-y-offset-m");
+ double target_z_offset_m = config->getDoubleValue("target-z-offset-m");
+
+ v = new View ( FG_LOOKAT, from_model, from_model_index,
+ at_model, at_model_index,
+ damp_roll, damp_pitch, damp_heading,
+ x_offset_m, y_offset_m,z_offset_m,
+ heading_offset_deg, pitch_offset_deg,
+ roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+ target_x_offset_m, target_y_offset_m,
+ target_z_offset_m, near_m, internal );
+ if (!from_model) {
+ v->_targetProperties.init(config, "target-");
+ }
+ } else {
+ v = new View ( FG_LOOKFROM, from_model, from_model_index,
+ false, 0, 0.0, 0.0, 0.0,
+ x_offset_m, y_offset_m, z_offset_m,
+ heading_offset_deg, pitch_offset_deg,
+ roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+ 0, 0, 0, near_m, internal );
+ }
+
+ if (!from_model) {
+ v->_eyeProperties.init(config, "eye-");
+ }
+
+ v->_name = config->getParent()->getStringValue("name");
+ v->_typeString = type;
+ v->_configHeadingOffsetDeg = config->getDoubleValue("default-heading-offset-deg");
+
+ return v;
+}
+
+
+// Destructor
+View::~View( void )
+{
+ _tiedProperties.Untie();
+}
+
+void
+View::init ()
+{
+}
+
+void
+View::bind ()
+{
+ _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
+ _tiedProperties.Tie("heading-offset-deg", this,
+ &View::getHeadingOffset_deg,
+ &View::setHeadingOffset_deg_property,
+ false /* do not set current property value */);
+
+ fgSetArchivable("/sim/current-view/heading-offset-deg");
+
+ _tiedProperties.Tie("goal-heading-offset-deg", this,
+ &View::getGoalHeadingOffset_deg,
+ &View::setGoalHeadingOffset_deg,
+ false /* do not set current property value */);
+
+ fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
+
+ _tiedProperties.Tie("pitch-offset-deg", this,
+ &View::getPitchOffset_deg,
+ &View::setPitchOffset_deg_property,
+ false /* do not set current property value */);
+ fgSetArchivable("/sim/current-view/pitch-offset-deg");
+ _tiedProperties.Tie("goal-pitch-offset-deg", this,
+ &View::getGoalPitchOffset_deg,
+ &View::setGoalPitchOffset_deg,
+ false /* do not set current property value */);
+ fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
+ _tiedProperties.Tie("roll-offset-deg", this,
+ &View::getRollOffset_deg,
+ &View::setRollOffset_deg_property,
+ false /* do not set current property value */);
+ fgSetArchivable("/sim/current-view/roll-offset-deg");
+ _tiedProperties.Tie("goal-roll-offset-deg", this,
+ &View::getGoalRollOffset_deg,
+ &View::setGoalRollOffset_deg,
+ false /* do not set current property value */);
+ fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
+
+
+ _tiedProperties.Tie("field-of-view", this,
+ &View::get_fov, &View::set_fov,
+ false);
+ fgSetArchivable("/sim/current-view/field-of-view");
+
+
+ _tiedProperties.Tie("aspect-ratio-multiplier", this,
+ &View::get_aspect_ratio_multiplier,
+ &View::set_aspect_ratio_multiplier,
+ false);
+
+ _tiedProperties.Tie("ground-level-nearplane-m", this,
+ &View::getNear_m, &View::setNear_m, false);
+ fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
+
+
+ _tiedProperties.Tie("viewer-lon-deg", this, &View::getLon_deg);
+ _tiedProperties.Tie("viewer-lat-deg", this, &View::getLat_deg);
+ _tiedProperties.Tie("viewer-elev-ft", this, &View::getElev_ft);
+
+ _tiedProperties.Tie("x-offset-m", this, &View::getXOffset_m,
+ &View::setXOffset_m, false);
+ _tiedProperties.Tie("y-offset-m", this, &View::getYOffset_m,
+ &View::setYOffset_m, false);
+ _tiedProperties.Tie("z-offset-m", this, &View::getZOffset_m,
+ &View::setZOffset_m, false);
+
+ _tiedProperties.Tie("target-x-offset-m", this, &View::getTargetXOffset_m,
+ &View::setTargetXOffset_m, false);
+ _tiedProperties.Tie("target-y-offset-m", this, &View::getTargetYOffset_m,
+ &View::setTargetYOffset_m, false);
+ _tiedProperties.Tie("target-z-offset-m", this, &View::getTargetZOffset_m,
+ &View::setTargetZOffset_m, false);
+
+// expose various quaternions under the debug/ subtree
+ _tiedProperties.Tie("debug/orientation-w", this, &View::getOrientation_w);
+ _tiedProperties.Tie("debug/orientation-x", this, &View::getOrientation_x);
+ _tiedProperties.Tie("debug/orientation-y", this, &View::getOrientation_y);
+ _tiedProperties.Tie("debug/orientation-z", this, &View::getOrientation_z);
+
+ _tiedProperties.Tie("debug/orientation_offset-w", this,
+ &View::getOrOffset_w);
+ _tiedProperties.Tie("debug/orientation_offset-x", this,
+ &View::getOrOffset_x);
+ _tiedProperties.Tie("debug/orientation_offset-y", this,
+ &View::getOrOffset_y);
+ _tiedProperties.Tie("debug/orientation_offset-z", this,
+ &View::getOrOffset_z);
+
+ _tiedProperties.Tie("debug/frame-w", this, &View::getFrame_w);
+ _tiedProperties.Tie("debug/frame-x", this, &View::getFrame_x);
+ _tiedProperties.Tie("debug/frame-y", this, &View::getFrame_y);
+ _tiedProperties.Tie("debug/frame-z", this, &View::getFrame_z);
+
+
+// expose the raw (OpenGL) orientation to the property tree,
+// for the sound-manager
+ _tiedProperties.Tie("raw-orientation", 0, this, &View::getRawOrientation_w);
+ _tiedProperties.Tie("raw-orientation", 1, this, &View::getRawOrientation_x);
+ _tiedProperties.Tie("raw-orientation", 2, this, &View::getRawOrientation_y);
+ _tiedProperties.Tie("raw-orientation", 3, this, &View::getRawOrientation_z);
+
+ _tiedProperties.Tie("viewer-x-m", this, &View::getAbsolutePosition_x);
+ _tiedProperties.Tie("viewer-y-m", this, &View::getAbsolutePosition_y);
+ _tiedProperties.Tie("viewer-z-m", this, &View::getAbsolutePosition_z);
+
+// following config properties are exposed on current-view but don't change,
+// so we can simply copy them here.
+ _tiedProperties.getRoot()->setStringValue("name", _name);
+ _tiedProperties.getRoot()->setStringValue("type", _typeString);
+ _tiedProperties.getRoot()->setBoolValue("internal", _internal);
+
+ SGPropertyNode_ptr config = _tiedProperties.getRoot()->getChild("config", 0, true);
+ config->setBoolValue("from-model", _from_model);
+ config->setDoubleValue("heading-offset-deg", _configHeadingOffsetDeg);
+ config->setDoubleValue("pitch-offset-deg", _configPitchOffsetDeg);
+ config->setDoubleValue("roll-offset-deg", _configRollOffsetDeg);
+ config->setDoubleValue("default-field-of-view-deg", _configFOV_deg);
+}
+
+void
+View::unbind ()
+{
+ _tiedProperties.Untie();
+}
+
+void View::resetOffsetsAndFOV()
+{
+ _target_offset_m = _configTargetOffset_m;
+ _offset_m = _configOffset_m;
+ _pitch_offset_deg = _configPitchOffsetDeg;
+ _heading_offset_deg = _configHeadingOffsetDeg;
+ _roll_offset_deg = _configRollOffsetDeg;
+ _fov_deg = _configFOV_deg;
+}
+
+void
+View::setType ( int type )
+{
+ if (type == 0)
+ _type = FG_LOOKFROM;
+ if (type == 1)
+ _type = FG_LOOKAT;
+}
+
+void
+View::setInternal ( bool internal )
+{
+ _internal = internal;
+}
+
+void
+View::setPosition (const SGGeod& geod)
+{
+ _dirty = true;
+ _position = geod;
+}
+
+void
+View::setTargetPosition (const SGGeod& geod)
+{
+ _dirty = true;
+ _target = geod;
+}
+
+void
+View::setRoll_deg (double roll_deg)
+{
+ _dirty = true;
+ _roll_deg = roll_deg;
+}
+
+void
+View::setPitch_deg (double pitch_deg)
+{
+ _dirty = true;
+ _pitch_deg = pitch_deg;
+}
+
+void
+View::setHeading_deg (double heading_deg)
+{
+ _dirty = true;
+ _heading_deg = heading_deg;
+}
+
+void
+View::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
+View::setTargetRoll_deg (double target_roll_deg)
+{
+ _dirty = true;
+ _target_roll_deg = target_roll_deg;
+}
+
+void
+View::setTargetPitch_deg (double target_pitch_deg)
+{
+ _dirty = true;
+ _target_pitch_deg = target_pitch_deg;
+}
+
+void
+View::setTargetHeading_deg (double target_heading_deg)
+{
+ _dirty = true;
+ _target_heading_deg = target_heading_deg;
+}
+
+void
+View::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
+{
+ _dirty = true;
+ _target_roll_deg = target_roll_deg;
+ _target_pitch_deg = target_pitch_deg;
+ _target_heading_deg = target_heading_deg;
+}
+
+void
+View::setXOffset_m (double x_offset_m)
+{
+ _dirty = true;
+ _offset_m.x() = x_offset_m;
+}
+
+void
+View::setYOffset_m (double y_offset_m)
+{
+ _dirty = true;
+ _offset_m.y() = y_offset_m;
+}
+
+void
+View::setZOffset_m (double z_offset_m)
+{
+ _dirty = true;
+ _offset_m.z() = z_offset_m;
+}
+
+void
+View::setTargetXOffset_m (double target_x_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.x() = target_x_offset_m;
+}
+
+void
+View::setTargetYOffset_m (double target_y_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.y() = target_y_offset_m;
+}
+
+void
+View::setTargetZOffset_m (double target_z_offset_m)
+{
+ _dirty = true;
+ _target_offset_m.z() = target_z_offset_m;
+}
+
+void
+View::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
+{
+ _dirty = true;
+ _offset_m.x() = x_offset_m;
+ _offset_m.y() = y_offset_m;
+ _offset_m.z() = z_offset_m;
+}
+
+void
+View::setRollOffset_deg (double roll_offset_deg)
+{
+ _dirty = true;
+ _roll_offset_deg = roll_offset_deg;
+}
+
+void
+View::setPitchOffset_deg (double pitch_offset_deg)
+{
+ _dirty = true;
+ _pitch_offset_deg = pitch_offset_deg;
+}
+
+void
+View::setHeadingOffset_deg (double heading_offset_deg)
+{
+ _dirty = true;
+ if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+ {
+ /* avoid optical effects (e.g. rotating sky) when "looking at" with
+ * heading offsets x==z==0 (view heading cannot change). */
+ _heading_offset_deg = 0.0;
+ }
+ else
+ _heading_offset_deg = heading_offset_deg;
+}
+
+void
+View::setHeadingOffset_deg_property (double heading_offset_deg)
+{
+ setHeadingOffset_deg(heading_offset_deg);
+ setGoalHeadingOffset_deg(heading_offset_deg);
+}
+
+void
+View::setPitchOffset_deg_property (double pitch_offset_deg)
+{
+ setPitchOffset_deg(pitch_offset_deg);
+ setGoalPitchOffset_deg(pitch_offset_deg);
+}
+
+void
+View::setRollOffset_deg_property (double roll_offset_deg)
+{
+ setRollOffset_deg(roll_offset_deg);
+ setGoalRollOffset_deg(roll_offset_deg);
+}
+
+void
+View::setGoalRollOffset_deg (double goal_roll_offset_deg)
+{
+ _dirty = true;
+ _goal_roll_offset_deg = goal_roll_offset_deg;
+}
+
+void
+View::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
+{
+ _dirty = true;
+ _goal_pitch_offset_deg = goal_pitch_offset_deg;
+ /* The angle is set to 1/1000th of a degree from the poles to avoid the
+ * singularity where the azimuthal angle becomes undefined, inducing optical
+ * artefacts. The arbitrary angle offset is visually unnoticeable while
+ * avoiding any possible floating point truncation artefacts. */
+ if ( _goal_pitch_offset_deg < -89.999 ) {
+ _goal_pitch_offset_deg = -89.999;
+ }
+ if ( _goal_pitch_offset_deg > 89.999 ) {
+ _goal_pitch_offset_deg = 89.999;
+ }
+
+}
+
+void
+View::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
+{
+ _dirty = true;
+ if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+ {
+ /* avoid optical effects (e.g. rotating sky) when "looking at" with
+ * heading offsets x==z==0 (view heading cannot change). */
+ _goal_heading_offset_deg = 0.0;
+ return;
+ }
+
+ _goal_heading_offset_deg = goal_heading_offset_deg;
+ while ( _goal_heading_offset_deg < 0.0 ) {
+ _goal_heading_offset_deg += 360;
+ }
+ while ( _goal_heading_offset_deg > 360 ) {
+ _goal_heading_offset_deg -= 360;
+ }
+}
+
+void
+View::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;
+}
+
+// recalc() is done every time one of the setters is called (making the
+// cached data "dirty") on the next "get". It calculates all the outputs
+// for viewer.
+void
+View::recalc ()
+{
+ if (_type == FG_LOOKFROM) {
+ recalcLookFrom();
+ } else {
+ recalcLookAt();
+ }
+
+ set_clean();
+}
+
+// recalculate for LookFrom view type...
+void
+View::recalcLookFrom ()
+{
+ // Update location data ...
+ if ( _from_model ) {
+ _position = globals->get_aircraft_position();
+ globals->get_aircraft_orientation(_heading_deg, _pitch_deg, _roll_deg);
+ }
+
+ double head = _heading_deg;
+ double pitch = _pitch_deg;
+ double roll = _roll_deg;
+ if ( !_from_model ) {
+ // update from our own data...
+ setDampTarget(roll, pitch, head);
+ getDampOutput(roll, pitch, head);
+ }
+
+ // The rotation rotating from the earth centerd frame to
+ // the horizontal local frame
+ SGQuatd hlOr = SGQuatd::fromLonLat(_position);
+
+ // The rotation from the horizontal local frame to the basic view orientation
+ SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+
+ // The rotation offset, don't know why heading is negative here ...
+ mViewOffsetOr
+ = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
+ _roll_offset_deg);
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ SGQuatd ec2body = hlOr*hlToBody;
+
+ // The cartesian position of the basic view coordinate
+ SGVec3d position = SGVec3d::fromGeod(_position);
+
+ // This is rotates the x-forward, y-right, z-down coordinate system the where
+ // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
+ SGQuatd q(-0.5, -0.5, 0.5, 0.5);
+
+ _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
+ mViewOrientation = ec2body*mViewOffsetOr*q;
+}
+
+void
+View::recalcLookAt ()
+{
+ // The geodetic position of our target to look at
+ if ( _at_model ) {
+ _target = globals->get_aircraft_position();
+ globals->get_aircraft_orientation(_target_heading_deg,
+ _target_pitch_deg,
+ _target_roll_deg);
+ } else {
+ // if not model then calculate our own target position...
+ setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ }
+
+ SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
+ _target_pitch_deg,
+ _target_roll_deg);
+ SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
+
+
+ if ( _from_model ) {
+ _position = globals->get_aircraft_position();
+ globals->get_aircraft_orientation(_heading_deg, _pitch_deg, _roll_deg);
+ } else {
+ // update from our own data, just the rotation here...
+ setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
+ getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
+ }
+ SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
+ SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
+
+ // the rotation offset, don't know why heading is negative here ...
+ mViewOffsetOr =
+ SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
+ _roll_offset_deg);
+
+ // Offsets to the eye position
+ SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
+ SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
+ SGVec3d eyeCart = SGVec3d::fromGeod(_position);
+ eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
+
+ SGVec3d atCart = SGVec3d::fromGeod(_target);
+
+ // add target offsets to at_position...
+ SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
+ -_target_offset_m.y());
+ target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
+ atCart += target_pos_off;
+ eyeCart += target_pos_off;
+
+ // Compute the eyepoints orientation and position
+ // wrt the earth centered frame - that is global coorinates
+ _absolute_view_pos = eyeCart;
+
+ // the view direction
+ SGVec3d dir = normalize(atCart - eyeCart);
+ // the up directon
+ SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
+ // rotate -dir to the 2-th unit vector
+ // rotate up to 1-th unit vector
+ // Note that this matches the OpenGL camera coordinate system
+ // with x-right, y-up, z-back.
+ mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
+}
+
+void
+View::setDampTarget(double roll, double pitch, double heading)
+{
+ _dampTarget = SGVec3d(roll, pitch, heading);
+}
+
+void
+View::getDampOutput(double& roll, double& pitch, double& heading)
+{
+ roll = _dampOutput[0];
+ pitch = _dampOutput[1];
+ heading = _dampOutput[2];
+}
+
+
+void
+View::updateDampOutput(double dt)
+{
+ static View *last_view = 0;
+ if ((last_view != this) || (dt > 1.0)) {
+ _dampOutput = _dampTarget;
+ last_view = this;
+ return;
+ }
+
+ const double interval = 0.01;
+ while (dt > interval) {
+
+ for (unsigned int i=0; i<3; ++i) {
+ if (_dampFactor[i] <= 0.0) {
+ // axis is un-damped, set output to target directly
+ _dampOutput[i] = _dampTarget[i];
+ continue;
+ }
+
+ double d = _dampOutput[i] - _dampTarget[i];
+ if (d > 180.0) {
+ _dampOutput[i] -= 360.0;
+ } else if (d < -180.0) {
+ _dampOutput[i] += 360.0;
+ }
+
+ _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) +
+ (_dampOutput[i] * (1.0 - _dampFactor[i]));
+ } // of axis iteration
+
+ dt -= interval;
+ } // of dt subdivision by interval
+}
+
+double
+View::get_h_fov()
+{
+ double aspectRatio = get_aspect_ratio();
+ switch (_scaling_type) {
+ case FG_SCALING_WIDTH: // h_fov == fov
+ return _fov_deg;
+ case FG_SCALING_MAX:
+ if (aspectRatio < 1.0) {
+ // h_fov == fov
+ return _fov_deg;
+ } else {
+ // v_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ / (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ }
+ default:
+ assert(false);
+ }
+ return 0.0;
+}
+
+
+
+double
+View::get_v_fov()
+{
+ double aspectRatio = get_aspect_ratio();
+ switch (_scaling_type) {
+ case FG_SCALING_WIDTH: // h_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ * (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ case FG_SCALING_MAX:
+ if (aspectRatio < 1.0) {
+ // h_fov == fov
+ return
+ atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+ * (aspectRatio*_aspect_ratio_multiplier))
+ * SG_RADIANS_TO_DEGREES * 2;
+ } else {
+ // v_fov == fov
+ return _fov_deg;
+ }
+ default:
+ assert(false);
+ }
+ return 0.0;
+}
+
+void
+View::updateData()
+{
+ if (!_from_model) {
+ SGGeod pos = _eyeProperties.position();
+ SGVec3d att = _eyeProperties.attitude();
+ setPosition(pos);
+ setOrientation(att[2], att[1], att[0]);
+ } else {
+ set_dirty();
+ }
+
+ // if lookat (type 1) then get target data...
+ if (getType() == FG_LOOKAT) {
+ if (!_from_model) {
+ SGGeod pos = _targetProperties.position();
+ SGVec3d att = _targetProperties.attitude();
+ setTargetPosition(pos);
+ setTargetOrientation(att[2], att[1], att[0]);
+ } else {
+ set_dirty();
+ }
+ }
+}
+
+void
+View::update (double dt)
+{
+ updateData();
+ updateDampOutput(dt);
+
+ int i;
+ int dt_ms = int(dt * 1000);
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
+ setHeadingOffset_deg( _goal_heading_offset_deg );
+ break;
+ } else {
+ // move current_view.headingoffset towards
+ // current_view.goal_view_offset
+ if ( _goal_heading_offset_deg > _heading_offset_deg )
+ {
+ if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
+ incHeadingOffset_deg( 0.5 );
+ } else {
+ incHeadingOffset_deg( -0.5 );
+ }
+ } else {
+ if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
+ incHeadingOffset_deg( -0.5 );
+ } else {
+ incHeadingOffset_deg( 0.5 );
+ }
+ }
+ if ( _heading_offset_deg > 360 ) {
+ incHeadingOffset_deg( -360 );
+ } else if ( _heading_offset_deg < 0 ) {
+ incHeadingOffset_deg( 360 );
+ }
+ }
+ }
+
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
+ setPitchOffset_deg( _goal_pitch_offset_deg );
+ break;
+ } else {
+ // move current_view.pitch_offset_deg towards
+ // current_view.goal_pitch_offset
+ if ( _goal_pitch_offset_deg > _pitch_offset_deg )
+ {
+ incPitchOffset_deg( 1.0 );
+ } else {
+ incPitchOffset_deg( -1.0 );
+ }
+ if ( _pitch_offset_deg > 90 ) {
+ setPitchOffset_deg(90);
+ } else if ( _pitch_offset_deg < -90 ) {
+ setPitchOffset_deg( -90 );
+ }
+ }
+ }
+
+
+ for ( i = 0; i < dt_ms; i++ ) {
+ if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
+ setRollOffset_deg( _goal_roll_offset_deg );
+ break;
+ } else {
+ // move current_view.roll_offset_deg towards
+ // current_view.goal_roll_offset
+ if ( _goal_roll_offset_deg > _roll_offset_deg )
+ {
+ incRollOffset_deg( 1.0 );
+ } else {
+ incRollOffset_deg( -1.0 );
+ }
+ if ( _roll_offset_deg > 90 ) {
+ setRollOffset_deg(90);
+ } else if ( _roll_offset_deg < -90 ) {
+ setRollOffset_deg( -90 );
+ }
+ }
+ }
+ recalc();
+}
+
+double View::getAbsolutePosition_x() const
+{
+ return _absolute_view_pos.x();
+}
+
+double View::getAbsolutePosition_y() const
+{
+ return _absolute_view_pos.y();
+}
+
+double View::getAbsolutePosition_z() const
+{
+ return _absolute_view_pos.z();
+}
+
+double View::getRawOrientation_w() const
+{
+ return mViewOrientation.w();
+}
+
+double View::getRawOrientation_x() const
+{
+ return mViewOrientation.x();
+}
+
+double View::getRawOrientation_y() const
+{
+ return mViewOrientation.y();
+}
+
+double View::getRawOrientation_z() const
+{
+ return mViewOrientation.z();
+}
+
+// This takes the conventional aviation XYZ body system
+// i.e. x=forward, y=starboard, z=bottom
+// which is widely used in FGFS
+// and rotates it into the OpenGL camera system
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
+static const SGQuatd fsb2sta()
+{
+ return SGQuatd(-0.5, -0.5, 0.5, 0.5);
+}
+
+// reference frame orientation.
+// This is the view orientation you get when you have no
+// view offset, i.e. the offset operator is the identity.
+//
+// For example, in the familiar "cockpit lookfrom" view,
+// the reference frame is equal to the aircraft attitude,
+// i.e. it is the view looking towards 12:00 straight ahead.
+//
+// FIXME: Somebody needs to figure out what is the reference
+// frame view for the other view modes.
+//
+// Conceptually, this quat represents a rotation relative
+// to the ECEF reference orientation, as described at
+// http://www.av8n.com/physics/coords.htm#sec-orientation
+//
+// See the NOTE concerning reference orientations, below.
+//
+// The components of this quat are expressed in
+// the conventional aviation basis set,
+// i.e. x=forward, y=starboard, z=bottom
+double View::getFrame_w() const
+{
+ return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).w();
+}
+
+double View::getFrame_x() const
+{
+ return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).x();
+}
+
+double View::getFrame_y() const
+{
+ return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).y();
+}
+
+double View::getFrame_z() const
+{
+ return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).z();
+}
+
+
+// view offset.
+// This rotation takes you from the aforementioned
+// reference frame view orientation to whatever
+// actual current view orientation is.
+//
+// The components of this quaternion are expressed in
+// the conventional aviation basis set,
+// i.e. x=forward, y=starboard, z=bottom
+double View::getOrOffset_w() const{
+ return mViewOffsetOr.w();
+}
+double View::getOrOffset_x() const{
+ return mViewOffsetOr.x();
+}
+double View::getOrOffset_y() const{
+ return mViewOffsetOr.y();
+}
+double View::getOrOffset_z() const{
+ return mViewOffsetOr.z();
+}
+
+
+// current view orientation.
+// This is a rotation relative to the earth-centered (ec)
+// reference frame.
+//
+// NOTE: Here we remove a factor of fsb2sta so that
+// the components of this quat are displayed using the
+// conventional ECEF basis set. This is *not* the way
+// the view orientation is stored in the views[] array,
+// but is easier for non-graphics hackers to understand.
+// If we did not remove this factor of fsb2sta here and
+// in getCurrentViewFrame, that would be equivalent to
+// the following peculiar reference orientation:
+// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
+// Then the reference frame orientation can be achieved via:
+// -- The aircraft X-axis (nose) headed south.
+// -- The aircraft Y-axis (starboard wingtip) pointing up.
+// -- The aircraft Z-axis (belly) pointing west.
+// To say the same thing in other words, and perhaps more to the
+// point: If we use the OpenGL camera orientation conventions,
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
+// aforementioned peculiar reference orientation at (lat,lon)
+// = (0,0) can be described as:
+// -- aircraft Xprime axis (starboard) pointed up
+// -- aircraft Yprime axis (top) pointed east
+// -- aircraft Zprime axis (aft) pointed north
+// meaning the OpenGL axes are aligned with the ECEF axes.
+double View::getOrientation_w() const{
+ return (mViewOrientation * conj(fsb2sta())).w();
+}
+double View::getOrientation_x() const{
+ return (mViewOrientation * conj(fsb2sta())).x();
+}
+double View::getOrientation_y() const{
+ return (mViewOrientation * conj(fsb2sta())).y();
+}
+double View::getOrientation_z() const{
+ return (mViewOrientation * conj(fsb2sta())).z();
+}
+
+double View::get_aspect_ratio() const
+{
+ return flightgear::CameraGroup::getDefault()->getMasterAspectRatio();
+}
+
+double View::getLon_deg() const
+{
+ return _position.getLongitudeDeg();
+}
+
+double View::getLat_deg() const
+{
+ return _position.getLatitudeDeg();
+}
+
+double View::getElev_ft() const
+{
+ return _position.getElevationFt();
+}
+
+View::PositionAttitudeProperties::PositionAttitudeProperties()
+{
+}
+
+View::PositionAttitudeProperties::~PositionAttitudeProperties()
+{
+}
+
+void View::PositionAttitudeProperties::init(SGPropertyNode_ptr parent, const std::string& prefix)
+{
+ _lonPathProp = parent->getNode(prefix + "lon-deg-path", true);
+ _latPathProp = parent->getNode(prefix + "lat-deg-path", true);
+ _altPathProp = parent->getNode(prefix + "alt-ft-path", true);
+ _headingPathProp = parent->getNode(prefix + "heading-deg-path", true);
+ _pitchPathProp = parent->getNode(prefix + "pitch-deg-path", true);
+ _rollPathProp = parent->getNode(prefix + "roll-deg-path", true);
+
+ // update the real properties now
+ valueChanged(NULL);
+
+ _lonPathProp->addChangeListener(this);
+ _latPathProp->addChangeListener(this);
+ _altPathProp->addChangeListener(this);
+ _headingPathProp->addChangeListener(this);
+ _pitchPathProp->addChangeListener(this);
+ _rollPathProp->addChangeListener(this);
+}
+
+void View::PositionAttitudeProperties::valueChanged(SGPropertyNode* node)
+{
+ _lonProp = resolvePathProperty(_lonPathProp);
+ _latProp = resolvePathProperty(_latPathProp);
+ _altProp = resolvePathProperty(_altPathProp);
+ _headingProp = resolvePathProperty(_headingPathProp);
+ _pitchProp = resolvePathProperty(_pitchPathProp);
+ _rollProp = resolvePathProperty(_rollPathProp);
+}
+
+SGPropertyNode_ptr View::PositionAttitudeProperties::resolvePathProperty(SGPropertyNode_ptr p)
+{
+ if (!p)
+ return SGPropertyNode_ptr();
+
+ std::string path = p->getStringValue();
+ if (path.empty())
+ return SGPropertyNode_ptr();
+
+ return fgGetNode(path, true);
+}
+
+SGGeod View::PositionAttitudeProperties::position() const
+{
+ double lon = _lonProp ? _lonProp->getDoubleValue() : 0.0;
+ double lat = _latProp ? _latProp->getDoubleValue() : 0.0;
+ double alt = _altProp ? _altProp->getDoubleValue() : 0.0;
+ return SGGeod::fromDegFt(lon, lat, alt);
+}
+
+SGVec3d View::PositionAttitudeProperties::attitude() const
+{
+ double heading = _headingProp ? _headingProp->getDoubleValue() : 0.0;
+ double pitch = _pitchProp ? _pitchProp->getDoubleValue() : 0.0;
+ double roll = _rollProp ? _rollProp->getDoubleValue() : 0.0;
+ return SGVec3d(heading, pitch, roll);
+}
--- /dev/null
+// view.hxx -- class for managing a view in the flightgear world.
+//
+// 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 - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _VIEWER_HXX
+#define _VIEWER_HXX
+
+
+#include <simgear/compiler.h>
+#include <simgear/constants.h>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/tiedpropertylist.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMath.hxx>
+
+#define FG_FOV_MIN 0.1
+#define FG_FOV_MAX 179.9
+
+namespace flightgear
+{
+
+// Define a structure containing view information
+class View : public SGSubsystem {
+
+public:
+
+ enum ScalingType { // 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
+ };
+
+ enum ViewType {
+ FG_LOOKFROM = 0,
+ FG_LOOKAT = 1
+ };
+
+ static View* createFromProperties(SGPropertyNode_ptr props);
+
+ // Destructor
+ virtual ~View();
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 1: standard SGSubsystem implementation.
+ //////////////////////////////////////////////////////////////////////
+
+ virtual void init ();
+ virtual void bind ();
+ virtual void unbind ();
+ virtual void update (double dt);
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 2: user settings.
+ //////////////////////////////////////////////////////////////////////
+
+ void resetOffsetsAndFOV();
+
+ ViewType getType() const { return _type; }
+ void setType( int type );
+
+ bool getInternal() const { return _internal; }
+ void setInternal( bool internal );
+
+ // Reference geodetic position of view from position...
+ // These are the actual aircraft position (pilot in
+ // pilot view, model in model view).
+ // FIXME: the model view position (ie target positions)
+ // should be in the model class.
+
+
+ const SGGeod& getPosition() const { return _position; }
+
+ // Reference geodetic target position...
+ const SGGeod& getTargetPosition() const { return _target; }
+
+
+
+ // Position offsets from reference
+ // These offsets position they "eye" in the scene according to a given
+ // location. For example in pilot view they are used to position the
+ // head inside the aircraft.
+ // Note that in pilot view these are applied "before" the orientation
+ // rotations (see below) so that the orientation rotations have the
+ // effect of the pilot staying in his seat and "looking out" in
+ // different directions.
+ // In chase view these are applied "after" the application of the
+ // orientation rotations listed below. This has the effect of the
+ // eye moving around and "looking at" the object (model) from
+ // different angles.
+ SGVec3d getOffset_m () const { return _offset_m; }
+ double getXOffset_m () const { return _offset_m.x(); }
+ double getYOffset_m () const { return _offset_m.y(); }
+ double getZOffset_m () const { return _offset_m.z(); }
+ double getTargetXOffset_m () const { return _target_offset_m.x(); }
+ double getTargetYOffset_m () const { return _target_offset_m.y(); }
+ double getTargetZOffset_m () const { return _target_offset_m.z(); }
+ void setXOffset_m (double x_offset_m);
+ void setYOffset_m (double y_offset_m);
+ void setZOffset_m (double z_offset_m);
+ void setTargetXOffset_m (double x_offset_m);
+ void setTargetYOffset_m (double y_offset_m);
+ void setTargetZOffset_m (double z_offset_m);
+ void setPositionOffsets (double x_offset_m,
+ double y_offset_m,
+ double z_offset_m);
+
+ // Reference orientation rotations...
+ // These are rotations that represent the plane attitude effect on
+ // the view (in Pilot view). IE The view frustrum rotates as the plane
+ // turns, pitches, and rolls.
+ // In model view (lookat/chaseview) these end up changing the angle that
+ // the eye is looking at the ojbect (ie the model).
+ // FIXME: the FGModel class should have its own version of these so that
+ // it can generate it's own model rotations.
+ double getHeading_deg () const {return _heading_deg; }
+
+
+ // Orientation offsets rotations from reference orientation.
+ // Goal settings are for smooth transition from prior
+ // offset when changing view direction.
+ // These offsets are in ADDITION to the orientation rotations listed
+ // above.
+ // In pilot view they are applied after the position offsets in order to
+ // give the effect of the pilot looking around.
+ // In lookat view they are applied before the position offsets so that
+ // the effect is the eye moving around looking at the object (ie the model)
+ // from different angles.
+ double getRollOffset_deg () const { return _roll_offset_deg; }
+ double getPitchOffset_deg () const { return _pitch_offset_deg; }
+ double getHeadingOffset_deg () const { return _heading_offset_deg; }
+
+ void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
+ void setHeadingOffset_deg (double heading_offset_deg);
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 3: output vectors and matrices in FlightGear coordinates.
+ //////////////////////////////////////////////////////////////////////
+
+ // Vectors and positions...
+
+ const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+ const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+ const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
+ const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 4: View and frustrum data setters and getters
+ //////////////////////////////////////////////////////////////////////
+
+ double get_fov() const { return _fov_deg; }
+ double get_h_fov(); // Get horizontal fov, in degrees.
+ double get_v_fov(); // Get vertical fov, in degrees.
+
+ // this is currently just a wrapper for the default CameraGroups' aspect
+ double get_aspect_ratio() const;
+
+ //////////////////////////////////////////////////////////////////////
+ // Part 5: misc setters and getters
+ //////////////////////////////////////////////////////////////////////
+
+ void set_dirty() { _dirty = true; }
+
+private:
+
+ // Constructor
+ View( ViewType Type, bool from_model, int from_model_index,
+ bool at_model, int at_model_index,
+ double damp_roll, double damp_pitch, double damp_heading,
+ double x_offset_m, double y_offset_m, double z_offset_m,
+ double heading_offset_deg, double pitch_offset_deg,
+ double roll_offset_deg,
+ double fov_deg, double aspect_ratio_multiplier,
+ double target_x_offset_m, double target_y_offset_m,
+ double target_z_offset_m, double near_m, bool internal );
+
+ void set_clean() { _dirty = false; }
+ void updateData();
+
+ void setHeadingOffset_deg_property (double heading_offset_deg);
+ void setPitchOffset_deg_property(double pitch_offset_deg);
+ void setRollOffset_deg_property(double roll_offset_deg);
+
+ void setPosition (const SGGeod& geod);
+ void setTargetPosition (const SGGeod& geod);
+
+ double getAbsolutePosition_x() const;
+ double getAbsolutePosition_y() const;
+ double getAbsolutePosition_z() const;
+
+ double getRawOrientation_w() const;
+ double getRawOrientation_x() const;
+ double getRawOrientation_y() const;
+ double getRawOrientation_z() const;
+
+ // quaternion accessors, for debugging:
+ double getFrame_w() const;
+ double getFrame_x() const;
+ double getFrame_y() const;
+ double getFrame_z() const;
+
+ double getOrientation_w() const;
+ double getOrientation_x() const;
+ double getOrientation_y() const;
+ double getOrientation_z() const;
+
+ double getOrOffset_w() const;
+ double getOrOffset_x() const;
+ double getOrOffset_y() const;
+ double getOrOffset_z() const;
+
+ double getLon_deg() const;
+ double getLat_deg() const;
+ double getElev_ft() const;
+
+ // Reference orientation rotations...
+ // These are rotations that represent the plane attitude effect on
+ // the view (in Pilot view). IE The view frustrum rotates as the plane
+ // turns, pitches, and rolls.
+ // In model view (lookat/chaseview) these end up changing the angle that
+ // the eye is looking at the ojbect (ie the model).
+ // FIXME: the FGModel class should have its own version of these so that
+ // it can generate it's own model rotations.
+ double getRoll_deg () const { return _roll_deg; }
+ double getPitch_deg () const {return _pitch_deg; }
+ void setRoll_deg (double roll_deg);
+ void setPitch_deg (double pitch_deg);
+ void setHeading_deg (double heading_deg);
+ void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
+ double getTargetRoll_deg () const { return _target_roll_deg; }
+ double getTargetPitch_deg () const {return _target_pitch_deg; }
+ double getTargetHeading_deg () const {return _target_heading_deg; }
+ void setTargetRoll_deg (double roll_deg);
+ void setTargetPitch_deg (double pitch_deg);
+ void setTargetHeading_deg (double heading_deg);
+ void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
+
+
+
+
+ // Orientation offsets rotations from reference orientation.
+ // Goal settings are for smooth transition from prior
+ // offset when changing view direction.
+ // These offsets are in ADDITION to the orientation rotations listed
+ // above.
+ // In pilot view they are applied after the position offsets in order to
+ // give the effect of the pilot looking around.
+ // In lookat view they are applied before the position offsets so that
+ // the effect is the eye moving around looking at the object (ie the model)
+ // from different angles.
+ double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
+ double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
+ double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
+ void setRollOffset_deg (double roll_offset_deg);
+ void setPitchOffset_deg (double pitch_offset_deg);
+ void setGoalRollOffset_deg (double goal_roll_offset_deg);
+ void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
+ void setOrientationOffsets (double roll_offset_deg,
+ double heading_offset_deg,
+ double pitch_offset_deg);
+
+ void set_aspect_ratio_multiplier( double m ) {
+ _aspect_ratio_multiplier = m;
+ }
+ double get_aspect_ratio_multiplier() const {
+ return _aspect_ratio_multiplier;
+ }
+
+ double getNear_m () const { return _ground_level_nearplane_m; }
+ void setNear_m (double near_m) {
+ _ground_level_nearplane_m = near_m;
+ }
+
+ void set_fov( double fov_deg ) {
+ _fov_deg = fov_deg;
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // private data //
+ //////////////////////////////////////////////////////////////////
+
+ std::string _name, _typeString;
+
+ // flag forcing a recalc of derived view parameters
+ bool _dirty;
+
+ simgear::TiedPropertyList _tiedProperties;
+
+ SGQuatd mViewOrientation;
+ SGQuatd mViewOffsetOr;
+ SGVec3d _absolute_view_pos;
+
+ SGGeod _position;
+ SGGeod _target;
+
+ double _roll_deg;
+ double _pitch_deg;
+ double _heading_deg;
+ double _target_roll_deg;
+ double _target_pitch_deg;
+ double _target_heading_deg;
+
+ double _configRollOffsetDeg,
+ _configHeadingOffsetDeg,
+ _configPitchOffsetDeg;
+
+ SGVec3d _dampTarget; ///< current target value we are damping towards
+ SGVec3d _dampOutput; ///< current output of damping filter
+ SGVec3d _dampFactor; ///< weighting of the damping filter
+
+ // Position offsets from FDM origin. The X axis is positive
+ // out the tail, Y is out the right wing, and Z is positive up.
+ // distance in meters
+ SGVec3d _offset_m;
+ SGVec3d _configOffset_m;
+
+ // Target offsets from FDM origin (for "lookat" targets) The X
+ // axis is positive out the tail, Y is out the right wing, and Z
+ // is positive up. distance in meters
+ SGVec3d _target_offset_m;
+ SGVec3d _configTargetOffset_m;
+
+ // orientation offsets from reference (_goal* are for smoothed transitions)
+ double _roll_offset_deg;
+ double _pitch_offset_deg;
+ double _heading_offset_deg;
+ double _goal_roll_offset_deg;
+ double _goal_pitch_offset_deg;
+ double _goal_heading_offset_deg;
+
+ // used to set nearplane when at ground level for this view
+ double _ground_level_nearplane_m;
+
+ ViewType _type;
+ ScalingType _scaling_type;
+
+ // internal view (e.g. cockpit) flag
+ bool _internal;
+
+ // view is looking from a model
+ bool _from_model;
+ int _from_model_index; // number of model (for multi model)
+
+ // view is looking at a model
+ bool _at_model;
+ int _at_model_index; // number of model (for multi model)
+
+ // the nominal field of view (angle, in degrees)
+ double _fov_deg;
+ double _configFOV_deg;
+ // default = 1.0, this value is user configurable and is
+ // multiplied into the aspect_ratio to get the actual vertical fov
+ double _aspect_ratio_multiplier;
+
+ class PositionAttitudeProperties : public SGPropertyChangeListener
+ {
+ public:
+ PositionAttitudeProperties();
+
+ void init(SGPropertyNode_ptr parent, const std::string& prefix);
+
+ virtual ~PositionAttitudeProperties();
+
+ SGGeod position() const;
+ SGVec3d attitude() const; // as heading pitch roll
+
+ protected:
+ virtual void valueChanged(SGPropertyNode* prop);
+
+ private:
+// disable copy
+ PositionAttitudeProperties(const PositionAttitudeProperties&);
+
+ SGPropertyNode_ptr resolvePathProperty(SGPropertyNode_ptr p);
+
+ SGPropertyNode_ptr _lonProp,
+ _latProp,
+ _altProp,
+ _headingProp,
+ _pitchProp,
+ _rollProp;
+ SGPropertyNode_ptr _lonPathProp,
+ _latPathProp,
+ _altPathProp,
+ _headingPathProp,
+ _pitchPathProp,
+ _rollPathProp;
+ };
+
+ PositionAttitudeProperties _eyeProperties;
+ PositionAttitudeProperties _targetProperties;
+
+ //////////////////////////////////////////////////////////////////
+ // private functions //
+ //////////////////////////////////////////////////////////////////
+
+ void recalc ();
+ void recalcLookFrom();
+ void recalcLookAt();
+
+ void setDampTarget(double h, double p, double r);
+ void getDampOutput(double& roll, double& pitch, double& heading);
+
+ void updateDampOutput(double dt);
+
+ // add to _heading_offset_deg
+ inline void incHeadingOffset_deg( double amt ) {
+ set_dirty();
+ _heading_offset_deg += amt;
+ }
+
+ // add to _pitch_offset_deg
+ inline void incPitchOffset_deg( double amt ) {
+ set_dirty();
+ _pitch_offset_deg += amt;
+ }
+
+ // add to _roll_offset_deg
+ inline void incRollOffset_deg( double amt ) {
+ set_dirty();
+ _roll_offset_deg += amt;
+ }
+
+}; // of class View
+
+} // of namespace flightgear
+
+
+#endif // _VIEWER_HXX
+++ /dev/null
-// viewer.cxx -- class for managing a viewer in the flightgear world.
-//
-// 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 - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "viewer.hxx"
-
-#include <simgear/compiler.h>
-#include <cassert>
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/constants.h>
-#include <simgear/scene/model/placement.hxx>
-#include <simgear/scene/util/OsgMath.hxx>
-
-#include <Main/fg_props.hxx>
-#include <Main/globals.hxx>
-#include "CameraGroup.hxx"
-
-using namespace flightgear;
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGViewer.
-////////////////////////////////////////////////////////////////////////
-
-// Constructor...
-View::View( ViewType Type, bool from_model, int from_model_index,
- bool at_model, int at_model_index,
- double damp_roll, double damp_pitch, double damp_heading,
- double x_offset_m, double y_offset_m, double z_offset_m,
- double heading_offset_deg, double pitch_offset_deg,
- double roll_offset_deg,
- double fov_deg, double aspect_ratio_multiplier,
- double target_x_offset_m, double target_y_offset_m,
- double target_z_offset_m, double near_m, bool internal ):
- _dirty(true),
- _roll_deg(0),
- _pitch_deg(0),
- _heading_deg(0),
- _target_roll_deg(0),
- _target_pitch_deg(0),
- _target_heading_deg(0),
- _scaling_type(FG_SCALING_MAX)
-{
- _absolute_view_pos = SGVec3d(0, 0, 0);
- _type = Type;
- _from_model = from_model;
- _from_model_index = from_model_index;
- _at_model = at_model;
- _at_model_index = at_model_index;
-
- _internal = internal;
-
- _dampFactor = SGVec3d::zeros();
- _dampOutput = SGVec3d::zeros();
- _dampTarget = SGVec3d::zeros();
-
- if (damp_roll > 0.0)
- _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
- if (damp_pitch > 0.0)
- _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
- if (damp_heading > 0.0)
- _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
-
- _offset_m.x() = x_offset_m;
- _offset_m.y() = y_offset_m;
- _offset_m.z() = z_offset_m;
- _configOffset_m = _offset_m;
-
- _heading_offset_deg = heading_offset_deg;
- _pitch_offset_deg = pitch_offset_deg;
- _roll_offset_deg = roll_offset_deg;
- _goal_heading_offset_deg = heading_offset_deg;
- _goal_pitch_offset_deg = pitch_offset_deg;
- _goal_roll_offset_deg = roll_offset_deg;
-
- _configHeadingOffsetDeg = heading_offset_deg;
- _configPitchOffsetDeg = pitch_offset_deg;
- _configRollOffsetDeg = roll_offset_deg;
-
- if (fov_deg > 0) {
- _fov_deg = fov_deg;
- } else {
- _fov_deg = 55;
- }
-
- _configFOV_deg = _fov_deg;
-
- _aspect_ratio_multiplier = aspect_ratio_multiplier;
- _target_offset_m.x() = target_x_offset_m;
- _target_offset_m.y() = target_y_offset_m;
- _target_offset_m.z() = target_z_offset_m;
- _configTargetOffset_m = _target_offset_m;
-
- _ground_level_nearplane_m = near_m;
- // a reasonable guess for init, so that the math doesn't blow up
-}
-
-View* View::createFromProperties(SGPropertyNode_ptr config)
-{
- double aspect_ratio_multiplier
- = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
-
- // find out if this is an internal view (e.g. in cockpit, low near plane)
- // FIXME : should be a child of config
- bool internal = config->getParent()->getBoolValue("internal", false);
-
-
- // FIXME:
- // this is assumed to be an aircraft model...we will need to read
- // model-from-type as well.
-
- // find out if this is a model we are looking from...
- bool from_model = config->getBoolValue("from-model");
- int from_model_index = config->getIntValue("from-model-idx");
-
- double x_offset_m = config->getDoubleValue("x-offset-m");
- double y_offset_m = config->getDoubleValue("y-offset-m");
- double z_offset_m = config->getDoubleValue("z-offset-m");
-
- double heading_offset_deg = config->getDoubleValue("heading-offset-deg");
- // config->setDoubleValue("heading-offset-deg", heading_offset_deg);
- double pitch_offset_deg = config->getDoubleValue("pitch-offset-deg");
- // config->setDoubleValue("pitch-offset-deg", pitch_offset_deg);
- double roll_offset_deg = config->getDoubleValue("roll-offset-deg");
- // config->setDoubleValue("roll-offset-deg", roll_offset_deg);
-
- double fov_deg = config->getDoubleValue("default-field-of-view-deg");
- double near_m = config->getDoubleValue("ground-level-nearplane-m");
-
- View* v = 0;
- // supporting two types "lookat" = 1 and "lookfrom" = 0
- const char *type = config->getParent()->getStringValue("type");
- if (!strcmp(type, "lookat")) {
- bool at_model = config->getBoolValue("at-model");
- int at_model_index = config->getIntValue("at-model-idx");
-
- double damp_roll = config->getDoubleValue("at-model-roll-damping");
- double damp_pitch = config->getDoubleValue("at-model-pitch-damping");
- double damp_heading = config->getDoubleValue("at-model-heading-damping");
-
- double target_x_offset_m = config->getDoubleValue("target-x-offset-m");
- double target_y_offset_m = config->getDoubleValue("target-y-offset-m");
- double target_z_offset_m = config->getDoubleValue("target-z-offset-m");
-
- v = new View ( FG_LOOKAT, from_model, from_model_index,
- at_model, at_model_index,
- damp_roll, damp_pitch, damp_heading,
- x_offset_m, y_offset_m,z_offset_m,
- heading_offset_deg, pitch_offset_deg,
- roll_offset_deg, fov_deg, aspect_ratio_multiplier,
- target_x_offset_m, target_y_offset_m,
- target_z_offset_m, near_m, internal );
- if (!from_model) {
- v->_targetProperties.init(config, "target-");
- }
- } else {
- v = new View ( FG_LOOKFROM, from_model, from_model_index,
- false, 0, 0.0, 0.0, 0.0,
- x_offset_m, y_offset_m, z_offset_m,
- heading_offset_deg, pitch_offset_deg,
- roll_offset_deg, fov_deg, aspect_ratio_multiplier,
- 0, 0, 0, near_m, internal );
- }
-
- if (!from_model) {
- v->_eyeProperties.init(config, "eye-");
- }
-
- v->_name = config->getParent()->getStringValue("name");
- v->_typeString = type;
- v->_configHeadingOffsetDeg = config->getDoubleValue("default-heading-offset-deg");
-
- return v;
-}
-
-
-// Destructor
-View::~View( void )
-{
- _tiedProperties.Untie();
-}
-
-void
-View::init ()
-{
-}
-
-void
-View::bind ()
-{
- _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
- _tiedProperties.Tie("heading-offset-deg", this,
- &View::getHeadingOffset_deg,
- &View::setHeadingOffset_deg_property,
- false /* do not set current property value */);
-
- fgSetArchivable("/sim/current-view/heading-offset-deg");
-
- _tiedProperties.Tie("goal-heading-offset-deg", this,
- &View::getGoalHeadingOffset_deg,
- &View::setGoalHeadingOffset_deg,
- false /* do not set current property value */);
-
- fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
-
- _tiedProperties.Tie("pitch-offset-deg", this,
- &View::getPitchOffset_deg,
- &View::setPitchOffset_deg_property,
- false /* do not set current property value */);
- fgSetArchivable("/sim/current-view/pitch-offset-deg");
- _tiedProperties.Tie("goal-pitch-offset-deg", this,
- &View::getGoalPitchOffset_deg,
- &View::setGoalPitchOffset_deg,
- false /* do not set current property value */);
- fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
- _tiedProperties.Tie("roll-offset-deg", this,
- &View::getRollOffset_deg,
- &View::setRollOffset_deg_property,
- false /* do not set current property value */);
- fgSetArchivable("/sim/current-view/roll-offset-deg");
- _tiedProperties.Tie("goal-roll-offset-deg", this,
- &View::getGoalRollOffset_deg,
- &View::setGoalRollOffset_deg,
- false /* do not set current property value */);
- fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
-
-
- _tiedProperties.Tie("field-of-view", this,
- &View::get_fov, &View::set_fov,
- false);
- fgSetArchivable("/sim/current-view/field-of-view");
-
-
- _tiedProperties.Tie("aspect-ratio-multiplier", this,
- &View::get_aspect_ratio_multiplier,
- &View::set_aspect_ratio_multiplier,
- false);
-
- _tiedProperties.Tie("ground-level-nearplane-m", this,
- &View::getNear_m, &View::setNear_m, false);
- fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
-
-
- _tiedProperties.Tie("viewer-lon-deg", this, &View::getLon_deg);
- _tiedProperties.Tie("viewer-lat-deg", this, &View::getLat_deg);
- _tiedProperties.Tie("viewer-elev-ft", this, &View::getElev_ft);
-
- _tiedProperties.Tie("x-offset-m", this, &View::getXOffset_m,
- &View::setXOffset_m, false);
- _tiedProperties.Tie("y-offset-m", this, &View::getYOffset_m,
- &View::setYOffset_m, false);
- _tiedProperties.Tie("z-offset-m", this, &View::getZOffset_m,
- &View::setZOffset_m, false);
-
- _tiedProperties.Tie("target-x-offset-m", this, &View::getTargetXOffset_m,
- &View::setTargetXOffset_m, false);
- _tiedProperties.Tie("target-y-offset-m", this, &View::getTargetYOffset_m,
- &View::setTargetYOffset_m, false);
- _tiedProperties.Tie("target-z-offset-m", this, &View::getTargetZOffset_m,
- &View::setTargetZOffset_m, false);
-
-// expose various quaternions under the debug/ subtree
- _tiedProperties.Tie("debug/orientation-w", this, &View::getOrientation_w);
- _tiedProperties.Tie("debug/orientation-x", this, &View::getOrientation_x);
- _tiedProperties.Tie("debug/orientation-y", this, &View::getOrientation_y);
- _tiedProperties.Tie("debug/orientation-z", this, &View::getOrientation_z);
-
- _tiedProperties.Tie("debug/orientation_offset-w", this,
- &View::getOrOffset_w);
- _tiedProperties.Tie("debug/orientation_offset-x", this,
- &View::getOrOffset_x);
- _tiedProperties.Tie("debug/orientation_offset-y", this,
- &View::getOrOffset_y);
- _tiedProperties.Tie("debug/orientation_offset-z", this,
- &View::getOrOffset_z);
-
- _tiedProperties.Tie("debug/frame-w", this, &View::getFrame_w);
- _tiedProperties.Tie("debug/frame-x", this, &View::getFrame_x);
- _tiedProperties.Tie("debug/frame-y", this, &View::getFrame_y);
- _tiedProperties.Tie("debug/frame-z", this, &View::getFrame_z);
-
-
-// expose the raw (OpenGL) orientation to the property tree,
-// for the sound-manager
- _tiedProperties.Tie("raw-orientation", 0, this, &View::getRawOrientation_w);
- _tiedProperties.Tie("raw-orientation", 1, this, &View::getRawOrientation_x);
- _tiedProperties.Tie("raw-orientation", 2, this, &View::getRawOrientation_y);
- _tiedProperties.Tie("raw-orientation", 3, this, &View::getRawOrientation_z);
-
- _tiedProperties.Tie("viewer-x-m", this, &View::getAbsolutePosition_x);
- _tiedProperties.Tie("viewer-y-m", this, &View::getAbsolutePosition_y);
- _tiedProperties.Tie("viewer-z-m", this, &View::getAbsolutePosition_z);
-
-// following config properties are exposed on current-view but don't change,
-// so we can simply copy them here.
- _tiedProperties.getRoot()->setStringValue("name", _name);
- _tiedProperties.getRoot()->setStringValue("type", _typeString);
- _tiedProperties.getRoot()->setBoolValue("internal", _internal);
-
- SGPropertyNode_ptr config = _tiedProperties.getRoot()->getChild("config", 0, true);
- config->setBoolValue("from-model", _from_model);
- config->setDoubleValue("heading-offset-deg", _configHeadingOffsetDeg);
- config->setDoubleValue("pitch-offset-deg", _configPitchOffsetDeg);
- config->setDoubleValue("roll-offset-deg", _configRollOffsetDeg);
- config->setDoubleValue("default-field-of-view-deg", _configFOV_deg);
-}
-
-void
-View::unbind ()
-{
- _tiedProperties.Untie();
-}
-
-void View::resetOffsetsAndFOV()
-{
- _target_offset_m = _configTargetOffset_m;
- _offset_m = _configOffset_m;
- _pitch_offset_deg = _configPitchOffsetDeg;
- _heading_offset_deg = _configHeadingOffsetDeg;
- _roll_offset_deg = _configRollOffsetDeg;
- _fov_deg = _configFOV_deg;
-}
-
-void
-View::setType ( int type )
-{
- if (type == 0)
- _type = FG_LOOKFROM;
- if (type == 1)
- _type = FG_LOOKAT;
-}
-
-void
-View::setInternal ( bool internal )
-{
- _internal = internal;
-}
-
-void
-View::setPosition (const SGGeod& geod)
-{
- _dirty = true;
- _position = geod;
-}
-
-void
-View::setTargetPosition (const SGGeod& geod)
-{
- _dirty = true;
- _target = geod;
-}
-
-void
-View::setRoll_deg (double roll_deg)
-{
- _dirty = true;
- _roll_deg = roll_deg;
-}
-
-void
-View::setPitch_deg (double pitch_deg)
-{
- _dirty = true;
- _pitch_deg = pitch_deg;
-}
-
-void
-View::setHeading_deg (double heading_deg)
-{
- _dirty = true;
- _heading_deg = heading_deg;
-}
-
-void
-View::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
-View::setTargetRoll_deg (double target_roll_deg)
-{
- _dirty = true;
- _target_roll_deg = target_roll_deg;
-}
-
-void
-View::setTargetPitch_deg (double target_pitch_deg)
-{
- _dirty = true;
- _target_pitch_deg = target_pitch_deg;
-}
-
-void
-View::setTargetHeading_deg (double target_heading_deg)
-{
- _dirty = true;
- _target_heading_deg = target_heading_deg;
-}
-
-void
-View::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
-{
- _dirty = true;
- _target_roll_deg = target_roll_deg;
- _target_pitch_deg = target_pitch_deg;
- _target_heading_deg = target_heading_deg;
-}
-
-void
-View::setXOffset_m (double x_offset_m)
-{
- _dirty = true;
- _offset_m.x() = x_offset_m;
-}
-
-void
-View::setYOffset_m (double y_offset_m)
-{
- _dirty = true;
- _offset_m.y() = y_offset_m;
-}
-
-void
-View::setZOffset_m (double z_offset_m)
-{
- _dirty = true;
- _offset_m.z() = z_offset_m;
-}
-
-void
-View::setTargetXOffset_m (double target_x_offset_m)
-{
- _dirty = true;
- _target_offset_m.x() = target_x_offset_m;
-}
-
-void
-View::setTargetYOffset_m (double target_y_offset_m)
-{
- _dirty = true;
- _target_offset_m.y() = target_y_offset_m;
-}
-
-void
-View::setTargetZOffset_m (double target_z_offset_m)
-{
- _dirty = true;
- _target_offset_m.z() = target_z_offset_m;
-}
-
-void
-View::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
-{
- _dirty = true;
- _offset_m.x() = x_offset_m;
- _offset_m.y() = y_offset_m;
- _offset_m.z() = z_offset_m;
-}
-
-void
-View::setRollOffset_deg (double roll_offset_deg)
-{
- _dirty = true;
- _roll_offset_deg = roll_offset_deg;
-}
-
-void
-View::setPitchOffset_deg (double pitch_offset_deg)
-{
- _dirty = true;
- _pitch_offset_deg = pitch_offset_deg;
-}
-
-void
-View::setHeadingOffset_deg (double heading_offset_deg)
-{
- _dirty = true;
- if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
- {
- /* avoid optical effects (e.g. rotating sky) when "looking at" with
- * heading offsets x==z==0 (view heading cannot change). */
- _heading_offset_deg = 0.0;
- }
- else
- _heading_offset_deg = heading_offset_deg;
-}
-
-void
-View::setHeadingOffset_deg_property (double heading_offset_deg)
-{
- setHeadingOffset_deg(heading_offset_deg);
- setGoalHeadingOffset_deg(heading_offset_deg);
-}
-
-void
-View::setPitchOffset_deg_property (double pitch_offset_deg)
-{
- setPitchOffset_deg(pitch_offset_deg);
- setGoalPitchOffset_deg(pitch_offset_deg);
-}
-
-void
-View::setRollOffset_deg_property (double roll_offset_deg)
-{
- setRollOffset_deg(roll_offset_deg);
- setGoalRollOffset_deg(roll_offset_deg);
-}
-
-void
-View::setGoalRollOffset_deg (double goal_roll_offset_deg)
-{
- _dirty = true;
- _goal_roll_offset_deg = goal_roll_offset_deg;
-}
-
-void
-View::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
-{
- _dirty = true;
- _goal_pitch_offset_deg = goal_pitch_offset_deg;
- /* The angle is set to 1/1000th of a degree from the poles to avoid the
- * singularity where the azimuthal angle becomes undefined, inducing optical
- * artefacts. The arbitrary angle offset is visually unnoticeable while
- * avoiding any possible floating point truncation artefacts. */
- if ( _goal_pitch_offset_deg < -89.999 ) {
- _goal_pitch_offset_deg = -89.999;
- }
- if ( _goal_pitch_offset_deg > 89.999 ) {
- _goal_pitch_offset_deg = 89.999;
- }
-
-}
-
-void
-View::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
-{
- _dirty = true;
- if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
- {
- /* avoid optical effects (e.g. rotating sky) when "looking at" with
- * heading offsets x==z==0 (view heading cannot change). */
- _goal_heading_offset_deg = 0.0;
- return;
- }
-
- _goal_heading_offset_deg = goal_heading_offset_deg;
- while ( _goal_heading_offset_deg < 0.0 ) {
- _goal_heading_offset_deg += 360;
- }
- while ( _goal_heading_offset_deg > 360 ) {
- _goal_heading_offset_deg -= 360;
- }
-}
-
-void
-View::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;
-}
-
-// recalc() is done every time one of the setters is called (making the
-// cached data "dirty") on the next "get". It calculates all the outputs
-// for viewer.
-void
-View::recalc ()
-{
- if (_type == FG_LOOKFROM) {
- recalcLookFrom();
- } else {
- recalcLookAt();
- }
-
- set_clean();
-}
-
-// recalculate for LookFrom view type...
-void
-View::recalcLookFrom ()
-{
- // Update location data ...
- if ( _from_model ) {
- _position = globals->get_aircraft_position();
- globals->get_aircraft_orientation(_heading_deg, _pitch_deg, _roll_deg);
- }
-
- double head = _heading_deg;
- double pitch = _pitch_deg;
- double roll = _roll_deg;
- if ( !_from_model ) {
- // update from our own data...
- setDampTarget(roll, pitch, head);
- getDampOutput(roll, pitch, head);
- }
-
- // The rotation rotating from the earth centerd frame to
- // the horizontal local frame
- SGQuatd hlOr = SGQuatd::fromLonLat(_position);
-
- // The rotation from the horizontal local frame to the basic view orientation
- SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
-
- // The rotation offset, don't know why heading is negative here ...
- mViewOffsetOr
- = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
- _roll_offset_deg);
-
- // Compute the eyepoints orientation and position
- // wrt the earth centered frame - that is global coorinates
- SGQuatd ec2body = hlOr*hlToBody;
-
- // The cartesian position of the basic view coordinate
- SGVec3d position = SGVec3d::fromGeod(_position);
-
- // This is rotates the x-forward, y-right, z-down coordinate system the where
- // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
- SGQuatd q(-0.5, -0.5, 0.5, 0.5);
-
- _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
- mViewOrientation = ec2body*mViewOffsetOr*q;
-}
-
-void
-View::recalcLookAt ()
-{
- // The geodetic position of our target to look at
- if ( _at_model ) {
- _target = globals->get_aircraft_position();
- globals->get_aircraft_orientation(_target_heading_deg,
- _target_pitch_deg,
- _target_roll_deg);
- } else {
- // if not model then calculate our own target position...
- setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
- getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
- }
-
- SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
- _target_pitch_deg,
- _target_roll_deg);
- SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
-
-
- if ( _from_model ) {
- _position = globals->get_aircraft_position();
- globals->get_aircraft_orientation(_heading_deg, _pitch_deg, _roll_deg);
- } else {
- // update from our own data, just the rotation here...
- setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
- getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
- }
- SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
- SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
-
- // the rotation offset, don't know why heading is negative here ...
- mViewOffsetOr =
- SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
- _roll_offset_deg);
-
- // Offsets to the eye position
- SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
- SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
- SGVec3d eyeCart = SGVec3d::fromGeod(_position);
- eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
-
- SGVec3d atCart = SGVec3d::fromGeod(_target);
-
- // add target offsets to at_position...
- SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
- -_target_offset_m.y());
- target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
- atCart += target_pos_off;
- eyeCart += target_pos_off;
-
- // Compute the eyepoints orientation and position
- // wrt the earth centered frame - that is global coorinates
- _absolute_view_pos = eyeCart;
-
- // the view direction
- SGVec3d dir = normalize(atCart - eyeCart);
- // the up directon
- SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
- // rotate -dir to the 2-th unit vector
- // rotate up to 1-th unit vector
- // Note that this matches the OpenGL camera coordinate system
- // with x-right, y-up, z-back.
- mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
-}
-
-void
-View::setDampTarget(double roll, double pitch, double heading)
-{
- _dampTarget = SGVec3d(roll, pitch, heading);
-}
-
-void
-View::getDampOutput(double& roll, double& pitch, double& heading)
-{
- roll = _dampOutput[0];
- pitch = _dampOutput[1];
- heading = _dampOutput[2];
-}
-
-
-void
-View::updateDampOutput(double dt)
-{
- static View *last_view = 0;
- if ((last_view != this) || (dt > 1.0)) {
- _dampOutput = _dampTarget;
- last_view = this;
- return;
- }
-
- const double interval = 0.01;
- while (dt > interval) {
-
- for (unsigned int i=0; i<3; ++i) {
- if (_dampFactor[i] <= 0.0) {
- // axis is un-damped, set output to target directly
- _dampOutput[i] = _dampTarget[i];
- continue;
- }
-
- double d = _dampOutput[i] - _dampTarget[i];
- if (d > 180.0) {
- _dampOutput[i] -= 360.0;
- } else if (d < -180.0) {
- _dampOutput[i] += 360.0;
- }
-
- _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) +
- (_dampOutput[i] * (1.0 - _dampFactor[i]));
- } // of axis iteration
-
- dt -= interval;
- } // of dt subdivision by interval
-}
-
-double
-View::get_h_fov()
-{
- double aspectRatio = get_aspect_ratio();
- switch (_scaling_type) {
- case FG_SCALING_WIDTH: // h_fov == fov
- return _fov_deg;
- case FG_SCALING_MAX:
- if (aspectRatio < 1.0) {
- // h_fov == fov
- return _fov_deg;
- } else {
- // v_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- / (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- }
- default:
- assert(false);
- }
- return 0.0;
-}
-
-
-
-double
-View::get_v_fov()
-{
- double aspectRatio = get_aspect_ratio();
- switch (_scaling_type) {
- case FG_SCALING_WIDTH: // h_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- * (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- case FG_SCALING_MAX:
- if (aspectRatio < 1.0) {
- // h_fov == fov
- return
- atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
- * (aspectRatio*_aspect_ratio_multiplier))
- * SG_RADIANS_TO_DEGREES * 2;
- } else {
- // v_fov == fov
- return _fov_deg;
- }
- default:
- assert(false);
- }
- return 0.0;
-}
-
-void
-View::updateData()
-{
- if (!_from_model) {
- SGGeod pos = _eyeProperties.position();
- SGVec3d att = _eyeProperties.attitude();
- setPosition(pos);
- setOrientation(att[2], att[1], att[0]);
- } else {
- set_dirty();
- }
-
- // if lookat (type 1) then get target data...
- if (getType() == FG_LOOKAT) {
- if (!_from_model) {
- SGGeod pos = _targetProperties.position();
- SGVec3d att = _targetProperties.attitude();
- setTargetPosition(pos);
- setTargetOrientation(att[2], att[1], att[0]);
- } else {
- set_dirty();
- }
- }
-}
-
-void
-View::update (double dt)
-{
- updateData();
- updateDampOutput(dt);
-
- int i;
- int dt_ms = int(dt * 1000);
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
- setHeadingOffset_deg( _goal_heading_offset_deg );
- break;
- } else {
- // move current_view.headingoffset towards
- // current_view.goal_view_offset
- if ( _goal_heading_offset_deg > _heading_offset_deg )
- {
- if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
- incHeadingOffset_deg( 0.5 );
- } else {
- incHeadingOffset_deg( -0.5 );
- }
- } else {
- if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
- incHeadingOffset_deg( -0.5 );
- } else {
- incHeadingOffset_deg( 0.5 );
- }
- }
- if ( _heading_offset_deg > 360 ) {
- incHeadingOffset_deg( -360 );
- } else if ( _heading_offset_deg < 0 ) {
- incHeadingOffset_deg( 360 );
- }
- }
- }
-
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
- setPitchOffset_deg( _goal_pitch_offset_deg );
- break;
- } else {
- // move current_view.pitch_offset_deg towards
- // current_view.goal_pitch_offset
- if ( _goal_pitch_offset_deg > _pitch_offset_deg )
- {
- incPitchOffset_deg( 1.0 );
- } else {
- incPitchOffset_deg( -1.0 );
- }
- if ( _pitch_offset_deg > 90 ) {
- setPitchOffset_deg(90);
- } else if ( _pitch_offset_deg < -90 ) {
- setPitchOffset_deg( -90 );
- }
- }
- }
-
-
- for ( i = 0; i < dt_ms; i++ ) {
- if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
- setRollOffset_deg( _goal_roll_offset_deg );
- break;
- } else {
- // move current_view.roll_offset_deg towards
- // current_view.goal_roll_offset
- if ( _goal_roll_offset_deg > _roll_offset_deg )
- {
- incRollOffset_deg( 1.0 );
- } else {
- incRollOffset_deg( -1.0 );
- }
- if ( _roll_offset_deg > 90 ) {
- setRollOffset_deg(90);
- } else if ( _roll_offset_deg < -90 ) {
- setRollOffset_deg( -90 );
- }
- }
- }
- recalc();
-}
-
-double View::getAbsolutePosition_x() const
-{
- return _absolute_view_pos.x();
-}
-
-double View::getAbsolutePosition_y() const
-{
- return _absolute_view_pos.y();
-}
-
-double View::getAbsolutePosition_z() const
-{
- return _absolute_view_pos.z();
-}
-
-double View::getRawOrientation_w() const
-{
- return mViewOrientation.w();
-}
-
-double View::getRawOrientation_x() const
-{
- return mViewOrientation.x();
-}
-
-double View::getRawOrientation_y() const
-{
- return mViewOrientation.y();
-}
-
-double View::getRawOrientation_z() const
-{
- return mViewOrientation.z();
-}
-
-// This takes the conventional aviation XYZ body system
-// i.e. x=forward, y=starboard, z=bottom
-// which is widely used in FGFS
-// and rotates it into the OpenGL camera system
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
-static const SGQuatd fsb2sta()
-{
- return SGQuatd(-0.5, -0.5, 0.5, 0.5);
-}
-
-// reference frame orientation.
-// This is the view orientation you get when you have no
-// view offset, i.e. the offset operator is the identity.
-//
-// For example, in the familiar "cockpit lookfrom" view,
-// the reference frame is equal to the aircraft attitude,
-// i.e. it is the view looking towards 12:00 straight ahead.
-//
-// FIXME: Somebody needs to figure out what is the reference
-// frame view for the other view modes.
-//
-// Conceptually, this quat represents a rotation relative
-// to the ECEF reference orientation, as described at
-// http://www.av8n.com/physics/coords.htm#sec-orientation
-//
-// See the NOTE concerning reference orientations, below.
-//
-// The components of this quat are expressed in
-// the conventional aviation basis set,
-// i.e. x=forward, y=starboard, z=bottom
-double View::getFrame_w() const
-{
- return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).w();
-}
-
-double View::getFrame_x() const
-{
- return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).x();
-}
-
-double View::getFrame_y() const
-{
- return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).y();
-}
-
-double View::getFrame_z() const
-{
- return ((mViewOrientation*conj(fsb2sta())*conj(mViewOffsetOr))).z();
-}
-
-
-// view offset.
-// This rotation takes you from the aforementioned
-// reference frame view orientation to whatever
-// actual current view orientation is.
-//
-// The components of this quaternion are expressed in
-// the conventional aviation basis set,
-// i.e. x=forward, y=starboard, z=bottom
-double View::getOrOffset_w() const{
- return mViewOffsetOr.w();
-}
-double View::getOrOffset_x() const{
- return mViewOffsetOr.x();
-}
-double View::getOrOffset_y() const{
- return mViewOffsetOr.y();
-}
-double View::getOrOffset_z() const{
- return mViewOffsetOr.z();
-}
-
-
-// current view orientation.
-// This is a rotation relative to the earth-centered (ec)
-// reference frame.
-//
-// NOTE: Here we remove a factor of fsb2sta so that
-// the components of this quat are displayed using the
-// conventional ECEF basis set. This is *not* the way
-// the view orientation is stored in the views[] array,
-// but is easier for non-graphics hackers to understand.
-// If we did not remove this factor of fsb2sta here and
-// in getCurrentViewFrame, that would be equivalent to
-// the following peculiar reference orientation:
-// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
-// Then the reference frame orientation can be achieved via:
-// -- The aircraft X-axis (nose) headed south.
-// -- The aircraft Y-axis (starboard wingtip) pointing up.
-// -- The aircraft Z-axis (belly) pointing west.
-// To say the same thing in other words, and perhaps more to the
-// point: If we use the OpenGL camera orientation conventions,
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
-// aforementioned peculiar reference orientation at (lat,lon)
-// = (0,0) can be described as:
-// -- aircraft Xprime axis (starboard) pointed up
-// -- aircraft Yprime axis (top) pointed east
-// -- aircraft Zprime axis (aft) pointed north
-// meaning the OpenGL axes are aligned with the ECEF axes.
-double View::getOrientation_w() const{
- return (mViewOrientation * conj(fsb2sta())).w();
-}
-double View::getOrientation_x() const{
- return (mViewOrientation * conj(fsb2sta())).x();
-}
-double View::getOrientation_y() const{
- return (mViewOrientation * conj(fsb2sta())).y();
-}
-double View::getOrientation_z() const{
- return (mViewOrientation * conj(fsb2sta())).z();
-}
-
-double View::get_aspect_ratio() const
-{
- return flightgear::CameraGroup::getDefault()->getMasterAspectRatio();
-}
-
-double View::getLon_deg() const
-{
- return _position.getLongitudeDeg();
-}
-
-double View::getLat_deg() const
-{
- return _position.getLatitudeDeg();
-}
-
-double View::getElev_ft() const
-{
- return _position.getElevationFt();
-}
-
-View::PositionAttitudeProperties::PositionAttitudeProperties()
-{
-}
-
-View::PositionAttitudeProperties::~PositionAttitudeProperties()
-{
-}
-
-void View::PositionAttitudeProperties::init(SGPropertyNode_ptr parent, const std::string& prefix)
-{
- _lonPathProp = parent->getNode(prefix + "lon-deg-path", true);
- _latPathProp = parent->getNode(prefix + "lat-deg-path", true);
- _altPathProp = parent->getNode(prefix + "alt-ft-path", true);
- _headingPathProp = parent->getNode(prefix + "heading-deg-path", true);
- _pitchPathProp = parent->getNode(prefix + "pitch-deg-path", true);
- _rollPathProp = parent->getNode(prefix + "roll-deg-path", true);
-
- // update the real properties now
- valueChanged(NULL);
-
- _lonPathProp->addChangeListener(this);
- _latPathProp->addChangeListener(this);
- _altPathProp->addChangeListener(this);
- _headingPathProp->addChangeListener(this);
- _pitchPathProp->addChangeListener(this);
- _rollPathProp->addChangeListener(this);
-}
-
-void View::PositionAttitudeProperties::valueChanged(SGPropertyNode* node)
-{
- _lonProp = resolvePathProperty(_lonPathProp);
- _latProp = resolvePathProperty(_latPathProp);
- _altProp = resolvePathProperty(_altPathProp);
- _headingProp = resolvePathProperty(_headingPathProp);
- _pitchProp = resolvePathProperty(_pitchPathProp);
- _rollProp = resolvePathProperty(_rollPathProp);
-}
-
-SGPropertyNode_ptr View::PositionAttitudeProperties::resolvePathProperty(SGPropertyNode_ptr p)
-{
- if (!p)
- return SGPropertyNode_ptr();
-
- std::string path = p->getStringValue();
- if (path.empty())
- return SGPropertyNode_ptr();
-
- return fgGetNode(path, true);
-}
-
-SGGeod View::PositionAttitudeProperties::position() const
-{
- double lon = _lonProp ? _lonProp->getDoubleValue() : 0.0;
- double lat = _latProp ? _latProp->getDoubleValue() : 0.0;
- double alt = _altProp ? _altProp->getDoubleValue() : 0.0;
- return SGGeod::fromDegFt(lon, lat, alt);
-}
-
-SGVec3d View::PositionAttitudeProperties::attitude() const
-{
- double heading = _headingProp ? _headingProp->getDoubleValue() : 0.0;
- double pitch = _pitchProp ? _pitchProp->getDoubleValue() : 0.0;
- double roll = _rollProp ? _rollProp->getDoubleValue() : 0.0;
- return SGVec3d(heading, pitch, roll);
-}
+++ /dev/null
-// viewer.hxx -- class for managing a viewer in the flightgear world.
-//
-// 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 - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _VIEWER_HXX
-#define _VIEWER_HXX
-
-
-#include <simgear/compiler.h>
-#include <simgear/constants.h>
-
-#include <simgear/props/props.hxx>
-#include <simgear/props/tiedpropertylist.hxx>
-#include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/math/SGMath.hxx>
-
-#define FG_FOV_MIN 0.1
-#define FG_FOV_MAX 179.9
-
-namespace flightgear
-{
-
-// Define a structure containing view information
-class View : public SGSubsystem {
-
-public:
-
- enum ScalingType { // 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
- };
-
- enum ViewType {
- FG_LOOKFROM = 0,
- FG_LOOKAT = 1
- };
-
- static View* createFromProperties(SGPropertyNode_ptr props);
-
- // Destructor
- virtual ~View();
-
- //////////////////////////////////////////////////////////////////////
- // Part 1: standard SGSubsystem implementation.
- //////////////////////////////////////////////////////////////////////
-
- virtual void init ();
- virtual void bind ();
- virtual void unbind ();
- virtual void update (double dt);
-
-
- //////////////////////////////////////////////////////////////////////
- // Part 2: user settings.
- //////////////////////////////////////////////////////////////////////
-
- void resetOffsetsAndFOV();
-
- ViewType getType() const { return _type; }
- void setType( int type );
-
- bool getInternal() const { return _internal; }
- void setInternal( bool internal );
-
- // Reference geodetic position of view from position...
- // These are the actual aircraft position (pilot in
- // pilot view, model in model view).
- // FIXME: the model view position (ie target positions)
- // should be in the model class.
-
-
- const SGGeod& getPosition() const { return _position; }
-
- // Reference geodetic target position...
- const SGGeod& getTargetPosition() const { return _target; }
-
-
-
- // Position offsets from reference
- // These offsets position they "eye" in the scene according to a given
- // location. For example in pilot view they are used to position the
- // head inside the aircraft.
- // Note that in pilot view these are applied "before" the orientation
- // rotations (see below) so that the orientation rotations have the
- // effect of the pilot staying in his seat and "looking out" in
- // different directions.
- // In chase view these are applied "after" the application of the
- // orientation rotations listed below. This has the effect of the
- // eye moving around and "looking at" the object (model) from
- // different angles.
- SGVec3d getOffset_m () const { return _offset_m; }
- double getXOffset_m () const { return _offset_m.x(); }
- double getYOffset_m () const { return _offset_m.y(); }
- double getZOffset_m () const { return _offset_m.z(); }
- double getTargetXOffset_m () const { return _target_offset_m.x(); }
- double getTargetYOffset_m () const { return _target_offset_m.y(); }
- double getTargetZOffset_m () const { return _target_offset_m.z(); }
- void setXOffset_m (double x_offset_m);
- void setYOffset_m (double y_offset_m);
- void setZOffset_m (double z_offset_m);
- void setTargetXOffset_m (double x_offset_m);
- void setTargetYOffset_m (double y_offset_m);
- void setTargetZOffset_m (double z_offset_m);
- void setPositionOffsets (double x_offset_m,
- double y_offset_m,
- double z_offset_m);
-
- // Reference orientation rotations...
- // These are rotations that represent the plane attitude effect on
- // the view (in Pilot view). IE The view frustrum rotates as the plane
- // turns, pitches, and rolls.
- // In model view (lookat/chaseview) these end up changing the angle that
- // the eye is looking at the ojbect (ie the model).
- // FIXME: the FGModel class should have its own version of these so that
- // it can generate it's own model rotations.
- double getHeading_deg () const {return _heading_deg; }
-
-
- // Orientation offsets rotations from reference orientation.
- // Goal settings are for smooth transition from prior
- // offset when changing view direction.
- // These offsets are in ADDITION to the orientation rotations listed
- // above.
- // In pilot view they are applied after the position offsets in order to
- // give the effect of the pilot looking around.
- // In lookat view they are applied before the position offsets so that
- // the effect is the eye moving around looking at the object (ie the model)
- // from different angles.
- double getRollOffset_deg () const { return _roll_offset_deg; }
- double getPitchOffset_deg () const { return _pitch_offset_deg; }
- double getHeadingOffset_deg () const { return _heading_offset_deg; }
-
- void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
- void setHeadingOffset_deg (double heading_offset_deg);
-
- //////////////////////////////////////////////////////////////////////
- // Part 3: output vectors and matrices in FlightGear coordinates.
- //////////////////////////////////////////////////////////////////////
-
- // Vectors and positions...
-
- const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
- const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
- const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
- const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
-
- //////////////////////////////////////////////////////////////////////
- // Part 4: View and frustrum data setters and getters
- //////////////////////////////////////////////////////////////////////
-
- double get_fov() const { return _fov_deg; }
- double get_h_fov(); // Get horizontal fov, in degrees.
- double get_v_fov(); // Get vertical fov, in degrees.
-
- // this is currently just a wrapper for the default CameraGroups' aspect
- double get_aspect_ratio() const;
-
- //////////////////////////////////////////////////////////////////////
- // Part 5: misc setters and getters
- //////////////////////////////////////////////////////////////////////
-
- void set_dirty() { _dirty = true; }
-
-private:
-
- // Constructor
- View( ViewType Type, bool from_model, int from_model_index,
- bool at_model, int at_model_index,
- double damp_roll, double damp_pitch, double damp_heading,
- double x_offset_m, double y_offset_m, double z_offset_m,
- double heading_offset_deg, double pitch_offset_deg,
- double roll_offset_deg,
- double fov_deg, double aspect_ratio_multiplier,
- double target_x_offset_m, double target_y_offset_m,
- double target_z_offset_m, double near_m, bool internal );
-
- void set_clean() { _dirty = false; }
- void updateData();
-
- void setHeadingOffset_deg_property (double heading_offset_deg);
- void setPitchOffset_deg_property(double pitch_offset_deg);
- void setRollOffset_deg_property(double roll_offset_deg);
-
- void setPosition (const SGGeod& geod);
- void setTargetPosition (const SGGeod& geod);
-
- double getAbsolutePosition_x() const;
- double getAbsolutePosition_y() const;
- double getAbsolutePosition_z() const;
-
- double getRawOrientation_w() const;
- double getRawOrientation_x() const;
- double getRawOrientation_y() const;
- double getRawOrientation_z() const;
-
- // quaternion accessors, for debugging:
- double getFrame_w() const;
- double getFrame_x() const;
- double getFrame_y() const;
- double getFrame_z() const;
-
- double getOrientation_w() const;
- double getOrientation_x() const;
- double getOrientation_y() const;
- double getOrientation_z() const;
-
- double getOrOffset_w() const;
- double getOrOffset_x() const;
- double getOrOffset_y() const;
- double getOrOffset_z() const;
-
- double getLon_deg() const;
- double getLat_deg() const;
- double getElev_ft() const;
-
- // Reference orientation rotations...
- // These are rotations that represent the plane attitude effect on
- // the view (in Pilot view). IE The view frustrum rotates as the plane
- // turns, pitches, and rolls.
- // In model view (lookat/chaseview) these end up changing the angle that
- // the eye is looking at the ojbect (ie the model).
- // FIXME: the FGModel class should have its own version of these so that
- // it can generate it's own model rotations.
- double getRoll_deg () const { return _roll_deg; }
- double getPitch_deg () const {return _pitch_deg; }
- void setRoll_deg (double roll_deg);
- void setPitch_deg (double pitch_deg);
- void setHeading_deg (double heading_deg);
- void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
- double getTargetRoll_deg () const { return _target_roll_deg; }
- double getTargetPitch_deg () const {return _target_pitch_deg; }
- double getTargetHeading_deg () const {return _target_heading_deg; }
- void setTargetRoll_deg (double roll_deg);
- void setTargetPitch_deg (double pitch_deg);
- void setTargetHeading_deg (double heading_deg);
- void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
-
-
-
-
- // Orientation offsets rotations from reference orientation.
- // Goal settings are for smooth transition from prior
- // offset when changing view direction.
- // These offsets are in ADDITION to the orientation rotations listed
- // above.
- // In pilot view they are applied after the position offsets in order to
- // give the effect of the pilot looking around.
- // In lookat view they are applied before the position offsets so that
- // the effect is the eye moving around looking at the object (ie the model)
- // from different angles.
- double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
- double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
- double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
- void setRollOffset_deg (double roll_offset_deg);
- void setPitchOffset_deg (double pitch_offset_deg);
- void setGoalRollOffset_deg (double goal_roll_offset_deg);
- void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
- void setOrientationOffsets (double roll_offset_deg,
- double heading_offset_deg,
- double pitch_offset_deg);
-
- void set_aspect_ratio_multiplier( double m ) {
- _aspect_ratio_multiplier = m;
- }
- double get_aspect_ratio_multiplier() const {
- return _aspect_ratio_multiplier;
- }
-
- double getNear_m () const { return _ground_level_nearplane_m; }
- void setNear_m (double near_m) {
- _ground_level_nearplane_m = near_m;
- }
-
- void set_fov( double fov_deg ) {
- _fov_deg = fov_deg;
- }
-
- //////////////////////////////////////////////////////////////////
- // private data //
- //////////////////////////////////////////////////////////////////
-
- std::string _name, _typeString;
-
- // flag forcing a recalc of derived view parameters
- bool _dirty;
-
- simgear::TiedPropertyList _tiedProperties;
-
- SGQuatd mViewOrientation;
- SGQuatd mViewOffsetOr;
- SGVec3d _absolute_view_pos;
-
- SGGeod _position;
- SGGeod _target;
-
- double _roll_deg;
- double _pitch_deg;
- double _heading_deg;
- double _target_roll_deg;
- double _target_pitch_deg;
- double _target_heading_deg;
-
- double _configRollOffsetDeg,
- _configHeadingOffsetDeg,
- _configPitchOffsetDeg;
-
- SGVec3d _dampTarget; ///< current target value we are damping towards
- SGVec3d _dampOutput; ///< current output of damping filter
- SGVec3d _dampFactor; ///< weighting of the damping filter
-
- // Position offsets from FDM origin. The X axis is positive
- // out the tail, Y is out the right wing, and Z is positive up.
- // distance in meters
- SGVec3d _offset_m;
- SGVec3d _configOffset_m;
-
- // Target offsets from FDM origin (for "lookat" targets) The X
- // axis is positive out the tail, Y is out the right wing, and Z
- // is positive up. distance in meters
- SGVec3d _target_offset_m;
- SGVec3d _configTargetOffset_m;
-
- // orientation offsets from reference (_goal* are for smoothed transitions)
- double _roll_offset_deg;
- double _pitch_offset_deg;
- double _heading_offset_deg;
- double _goal_roll_offset_deg;
- double _goal_pitch_offset_deg;
- double _goal_heading_offset_deg;
-
- // used to set nearplane when at ground level for this view
- double _ground_level_nearplane_m;
-
- ViewType _type;
- ScalingType _scaling_type;
-
- // internal view (e.g. cockpit) flag
- bool _internal;
-
- // view is looking from a model
- bool _from_model;
- int _from_model_index; // number of model (for multi model)
-
- // view is looking at a model
- bool _at_model;
- int _at_model_index; // number of model (for multi model)
-
- // the nominal field of view (angle, in degrees)
- double _fov_deg;
- double _configFOV_deg;
- // default = 1.0, this value is user configurable and is
- // multiplied into the aspect_ratio to get the actual vertical fov
- double _aspect_ratio_multiplier;
-
- class PositionAttitudeProperties : public SGPropertyChangeListener
- {
- public:
- PositionAttitudeProperties();
-
- void init(SGPropertyNode_ptr parent, const std::string& prefix);
-
- virtual ~PositionAttitudeProperties();
-
- SGGeod position() const;
- SGVec3d attitude() const; // as heading pitch roll
-
- protected:
- virtual void valueChanged(SGPropertyNode* prop);
-
- private:
-// disable copy
- PositionAttitudeProperties(const PositionAttitudeProperties&);
-
- SGPropertyNode_ptr resolvePathProperty(SGPropertyNode_ptr p);
-
- SGPropertyNode_ptr _lonProp,
- _latProp,
- _altProp,
- _headingProp,
- _pitchProp,
- _rollProp;
- SGPropertyNode_ptr _lonPathProp,
- _latPathProp,
- _altPathProp,
- _headingPathProp,
- _pitchPathProp,
- _rollPathProp;
- };
-
- PositionAttitudeProperties _eyeProperties;
- PositionAttitudeProperties _targetProperties;
-
- //////////////////////////////////////////////////////////////////
- // private functions //
- //////////////////////////////////////////////////////////////////
-
- void recalc ();
- void recalcLookFrom();
- void recalcLookAt();
-
- void setDampTarget(double h, double p, double r);
- void getDampOutput(double& roll, double& pitch, double& heading);
-
- void updateDampOutput(double dt);
-
- // add to _heading_offset_deg
- inline void incHeadingOffset_deg( double amt ) {
- set_dirty();
- _heading_offset_deg += amt;
- }
-
- // add to _pitch_offset_deg
- inline void incPitchOffset_deg( double amt ) {
- set_dirty();
- _pitch_offset_deg += amt;
- }
-
- // add to _roll_offset_deg
- inline void incRollOffset_deg( double amt ) {
- set_dirty();
- _roll_offset_deg += amt;
- }
-
-}; // of class View
-
-} // of namespace flightgear
-
-
-#endif // _VIEWER_HXX
#include <simgear/scene/util/OsgMath.hxx>
#include <Main/fg_props.hxx>
-#include "viewer.hxx"
+#include "view.hxx"
#include "CameraGroup.hxx"
SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
return;
}
-
+
inited = true;
for (unsigned int i = 0; i < config_list.size(); i++) {
if (!inited) {
return;
}
-
+
inited = false;
views.clear();
}