fgfs.cxx fgfs.hxx \
globals.cxx globals.hxx \
logger.cxx logger.hxx \
- model.cxx model.hxx \
options.cxx options.hxx \
splash.cxx splash.hxx \
viewer.cxx viewer.hxx \
$(top_builddir)/src/FDM/LaRCsim/libLaRCsim.a \
$(top_builddir)/src/FDM/UIUCModel/libUIUCModel.a \
$(top_builddir)/src/GUI/libGUI.a \
+ $(top_builddir)/src/Model/libModel.a \
$(top_builddir)/src/Navaids/libNavaids.a \
$(top_builddir)/src/Scenery/libScenery.a \
$(top_builddir)/src/Sound/libSound.a \
methods; eventually, this will be a short, simple file defining the
top-level flow logic of the program.
-model.cxx
-model.hxx
- This module defines the FGAircraftModel subsystem, which controls
- the display and animation of 3D models in FlightGear.
-
options.cxx
options.hxx
This module defines global functions for parsing command-line
#include <FDM/UIUCModel/uiuc_aircraftdir.h>
#include <GUI/gui.h>
+#include <Model/acmodel.hxx>
#ifdef FG_NETWORK_OLK
#include <NetworkOLK/network.h>
#endif
#include "viewmgr.hxx"
#include "options.hxx"
#include "logger.hxx"
-#include "model.hxx"
#ifdef macintosh
# include <console.h> // -dw- for command line dialog
+++ /dev/null
-// model.cxx - manage a 3D aircraft model.
-// Written by David Megginson, started 2002.
-//
-// This file is in the Public Domain, and comes with no warranty.
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <string.h> // for strcmp()
-
-#include <plib/sg.h>
-#include <plib/ssg.h>
-
-#include <simgear/compiler.h>
-#include <simgear/debug/logstream.hxx>
-#include <simgear/misc/exception.hxx>
-#include <simgear/misc/sg_path.hxx>
-
-#include "globals.hxx"
-#include "fg_props.hxx"
-#include "viewmgr.hxx"
-#include "model.hxx"
-
-extern ssgRoot * cockpit; // FIXME: from main.cxx
-
-FGAircraftModel current_model; // FIXME: add to globals
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Static utility functions.
-////////////////////////////////////////////////////////////////////////
-
-/**
- * Locate a named SSG node in a branch.
- */
-static ssgEntity *
-find_named_node (ssgEntity * node, const char * name)
-{
- char * node_name = node->getName();
- if (node_name != 0 && !strcmp(name, node_name))
- return node;
- else if (node->isAKindOf(ssgTypeBranch())) {
- int nKids = node->getNumKids();
- for (int i = 0; i < nKids; i++) {
- ssgEntity * result =
- find_named_node(((ssgBranch*)node)->getKid(i), name);
- if (result != 0)
- return result;
- }
- }
- return 0;
-}
-
-/**
- * Splice a branch in between all child nodes and their parents.
- */
-static void
-splice_branch (ssgBranch * branch, ssgEntity * child)
-{
- int nParents = child->getNumParents();
- branch->addKid(child);
- for (int i = 0; i < nParents; i++) {
- ssgBranch * parent = child->getParent(i);
- parent->replaceKid(child, branch);
- }
-}
-
-/**
- * Set up the transform matrix for a spin or rotation.
- */
-static void
-set_rotation (sgMat4 &matrix, double position_deg,
- sgVec3 ¢er, sgVec3 &axis)
-{
- float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
-
- float s = (float) sin ( temp_angle ) ;
- float c = (float) cos ( temp_angle ) ;
- float t = SG_ONE - c ;
-
- // axis was normalized at load time
- // hint to the compiler to put these into FP registers
- float x = axis[0];
- float y = axis[1];
- float z = axis[2];
-
- matrix[0][0] = t * x * x + c ;
- matrix[0][1] = t * y * x - s * z ;
- matrix[0][2] = t * z * x + s * y ;
- matrix[0][3] = SG_ZERO;
-
- matrix[1][0] = t * x * y + s * z ;
- matrix[1][1] = t * y * y + c ;
- matrix[1][2] = t * z * y - s * x ;
- matrix[1][3] = SG_ZERO;
-
- matrix[2][0] = t * x * z - s * y ;
- matrix[2][1] = t * y * z + s * x ;
- matrix[2][2] = t * z * z + c ;
- matrix[2][3] = SG_ZERO;
-
- // hint to the compiler to put these into FP registers
- x = center[0];
- y = center[1];
- z = center[2];
-
- matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
- matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
- matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
- matrix[3][3] = SG_ONE;
-}
-
-/**
- * Set up the transform matrix for a translation.
- */
-static void
-set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
-{
- sgVec3 xyz;
- sgScaleVec3(xyz, axis, position_m);
- sgMakeTransMat4(matrix, xyz);
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::FGAircraftModel ()
- : _model(0),
- _selector(new ssgSelector),
- _position(new ssgTransform)
-{
-}
-
-FGAircraftModel::~FGAircraftModel ()
-{
- // since the nodes are attached to the scene graph, they'll be
- // deleted automatically
-
- for (int i = 0; i < _animations.size(); i++) {
- Animation * tmp = _animations[i];
- _animations[i] = 0;
- delete tmp;
- }
-
-}
-
-void
-FGAircraftModel::init ()
-{
- // TODO: optionally load an XML file with a pointer to the 3D object
- // and placement and animation info
-
- SGPropertyNode props;
-
- SG_LOG(SG_INPUT, SG_INFO, "Initializing aircraft 3D model");
-
- // Load the 3D aircraft object itself
- // DCL - the xml parser requires the full path but the ssgLoader doesn't
- // so lets have two paths.
- SGPath xmlpath = globals->get_fg_root();
- SGPath modelpath = (string)fgGetString("/sim/model/path", "Models/Geometry/glider.ac");
- xmlpath.append(modelpath.str());
-
- if (xmlpath.str().substr(xmlpath.str().size() - 4, 4) == ".xml") {
- readProperties(xmlpath.str(), &props);
- if (props.hasValue("/path")) {
- modelpath = modelpath.dir();
- modelpath.append(props.getStringValue("/path"));
- } else {
- modelpath = "Models/Geometry/glider.ac";
- }
- }
-
- ssgTexturePath((char *)xmlpath.dir().c_str());
- _model = ssgLoad((char *)modelpath.c_str());
- if (_model == 0) {
- _model = ssgLoad((char *)"Models/Geometry/glider.ac");
- if (_model == 0)
- throw sg_exception("Failed to load an aircraft model");
- }
-
- // Load animations
- vector<SGPropertyNode *> animation_nodes = props.getChildren("animation");
- for (unsigned int i = 0; i < animation_nodes.size(); i++) {
- vector<SGPropertyNode *> name_nodes =
- animation_nodes[i]->getChildren("object-name");
- if (name_nodes.size() < 1) {
- SG_LOG(SG_INPUT, SG_ALERT, "No object-name given for transformation");
- } else {
- for (unsigned int j = 0; j < name_nodes.size(); j++) {
- Animation * animation =
- make_animation(name_nodes[j]->getStringValue(), animation_nodes[i]);
- if (animation != 0)
- _animations.push_back(animation);
- }
- }
- }
-
- // Set up the alignment node
- ssgTransform * align = new ssgTransform;
- align->addKid(_model);
- sgMat4 rot_matrix;
- sgMat4 off_matrix;
- sgMat4 res_matrix;
- float h_rot = props.getFloatValue("/offsets/heading-deg", 0.0);
- float p_rot = props.getFloatValue("/offsets/roll-deg", 0.0);
- float r_rot = props.getFloatValue("/offsets/pitch-deg", 0.0);
- float x_off = props.getFloatValue("/offsets/x-m", 0.0);
- float y_off = props.getFloatValue("/offsets/y-m", 0.0);
- float z_off = props.getFloatValue("/offsets/z-m", 0.0);
- sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
- sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
- sgMultMat4(res_matrix, off_matrix, rot_matrix);
- align->setTransform(res_matrix);
-
- // Set up the position node
- _position->addKid(align);
-
- // Set up the selector node
- _selector->addKid(_position);
- _selector->clrTraversalMaskBits(SSGTRAV_HOT);
- cockpit->addKid(_selector);
-}
-
-void
-FGAircraftModel::bind ()
-{
-}
-
-void
-FGAircraftModel::unbind ()
-{
-}
-
-void
-FGAircraftModel::update (int dt)
-{
- sgMat4 MODEL_ROT, LOCAL;
- sgMat4 sgTRANS;
-
- int view_number = globals->get_viewmgr()->get_current();
-
- if (view_number == 0 && !fgGetBool("/sim/view/internal")) {
- _selector->select(false);
- } else {
- for (unsigned int i = 0; i < _animations.size(); i++)
- _animations[i]->update(dt);
-
- _selector->select(true);
- FGViewer *current_view =
- (FGViewer *)globals->get_viewmgr()->get_view( view_number );
-
- // FIXME: this class needs to be unlinked from the viewer
- // get transform for current position in the world...
- sgMakeTransMat4( sgTRANS, current_view->getRelativeViewPos() );
-
- // get a copy of the LOCAL rotation from the current view...
- sgCopyMat4( LOCAL, current_view->get_LOCAL_ROT() );
-
- // Make the MODEL Rotation (just reordering the LOCAL matrix
- // and flipping the model over on its feet)...
- MODEL_ROT[0][0] = -LOCAL[2][0];
- MODEL_ROT[0][1] = -LOCAL[2][1];
- MODEL_ROT[0][2] = -LOCAL[2][2];
- MODEL_ROT[0][3] = SG_ZERO;
- MODEL_ROT[1][0] = LOCAL[1][0];
- MODEL_ROT[1][1] = LOCAL[1][1];
- MODEL_ROT[1][2] = LOCAL[1][2];
- MODEL_ROT[1][3] = SG_ZERO;
- MODEL_ROT[2][0] = LOCAL[0][0];
- MODEL_ROT[2][1] = LOCAL[0][1];
- MODEL_ROT[2][2] = LOCAL[0][2];
- MODEL_ROT[2][3] = SG_ZERO;
-
- // add the position data to the matrix
- MODEL_ROT[3][0] = SG_ZERO;
- MODEL_ROT[3][1] = SG_ZERO;
- MODEL_ROT[3][2] = SG_ZERO;
- MODEL_ROT[3][3] = SG_ONE;
-
- sgPostMultMat4( MODEL_ROT, sgTRANS );
-
- sgCoord tuxpos;
- sgSetCoord( &tuxpos, MODEL_ROT );
- _position->setTransform( &tuxpos );
- }
-}
-
-FGAircraftModel::Animation *
-FGAircraftModel::make_animation (const char * object_name,
- SGPropertyNode * node)
-{
- Animation * animation = 0;
- const char * type = node->getStringValue("type");
- if (!strcmp("none", type)) {
- animation = new NullAnimation();
- } else if (!strcmp("select", type)) {
- animation = new SelectAnimation();
- } else if (!strcmp("spin", type)) {
- animation = new SpinAnimation();
- } else if (!strcmp("rotate", type)) {
- animation = new RotateAnimation();
- } else if (!strcmp("translate", type)) {
- animation = new TranslateAnimation();
- } else {
- animation = new NullAnimation();
- SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
- }
-
- ssgEntity * object = find_named_node(_model, object_name);
- if (object == 0) {
- SG_LOG(SG_INPUT, SG_WARN, "Object " << object_name << " not found");
- delete animation;
- animation = 0;
- } else {
- animation->init(object, node);
- }
-
- return animation;
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::Animation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::Animation::Animation ()
-{
-}
-
-FGAircraftModel::Animation::~Animation ()
-{
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::NullAnimation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::NullAnimation::NullAnimation ()
- : _branch(new ssgBranch)
-{
-}
-
-FGAircraftModel::NullAnimation::~NullAnimation ()
-{
- _branch = 0;
-}
-
-void
-FGAircraftModel::NullAnimation::init (ssgEntity * object,
- SGPropertyNode * props)
-{
- splice_branch(_branch, object);
- _branch->setName(props->getStringValue("name", 0));
-}
-
-void
-FGAircraftModel::NullAnimation::update (int dt)
-{
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::SelectAnimation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::SelectAnimation::SelectAnimation ()
- : _condition(0),
- _selector(new ssgSelector)
-{
-}
-
-FGAircraftModel::SelectAnimation::~SelectAnimation ()
-{
- delete _condition;
- _selector = 0;
-}
-
-void
-FGAircraftModel::SelectAnimation::init (ssgEntity * object,
- SGPropertyNode * props)
-{
- splice_branch(_selector, object);
- _selector->setName(props->getStringValue("name", 0));
- SGPropertyNode * node = props->getChild("condition");
- if (node != 0) {
- _condition = fgReadCondition(node);
- }
-}
-
-void
-FGAircraftModel::SelectAnimation::update (int dt)
-{
- if (_condition != 0 && _condition->test())
- _selector->select(0xffff);
- else
- _selector->select(0x0000);
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::SpinAnimation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::SpinAnimation::SpinAnimation ()
- : _prop(0),
- _factor(0),
- _position_deg(0),
- _transform(new ssgTransform)
-{
-}
-
-FGAircraftModel::SpinAnimation::~SpinAnimation ()
-{
- _transform = 0;
-}
-
-void
-FGAircraftModel::SpinAnimation::init (ssgEntity * object,
- SGPropertyNode * props)
-{
- // Splice in the new transform node
- splice_branch(_transform, object);
- _transform->setName(props->getStringValue("name", 0));
- _prop = fgGetNode(props->getStringValue("property", "/null"), true);
- _factor = props->getDoubleValue("factor", 1.0);
- _position_deg = props->getDoubleValue("starting-position-deg", 0);
- _center[0] = props->getFloatValue("center/x-m", 0);
- _center[1] = props->getFloatValue("center/y-m", 0);
- _center[2] = props->getFloatValue("center/z-m", 0);
- _axis[0] = props->getFloatValue("axis/x", 0);
- _axis[1] = props->getFloatValue("axis/y", 0);
- _axis[2] = props->getFloatValue("axis/z", 0);
- sgNormalizeVec3(_axis);
-}
-
-void
-FGAircraftModel::SpinAnimation::update (int dt)
-{
- float velocity_rpms = (_prop->getDoubleValue() * _factor / 60000.0);
- _position_deg += (dt * velocity_rpms * 360);
- while (_position_deg < 0)
- _position_deg += 360.0;
- while (_position_deg >= 360.0)
- _position_deg -= 360.0;
- set_rotation(_matrix, _position_deg, _center, _axis);
- _transform->setTransform(_matrix);
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::RotateAnimation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::RotateAnimation::RotateAnimation ()
- : _prop(0),
- _offset_deg(0.0),
- _factor(1.0),
- _has_min(false),
- _min_deg(0.0),
- _has_max(false),
- _max_deg(1.0),
- _position_deg(0.0),
- _transform(new ssgTransform)
-{
-}
-
-FGAircraftModel::RotateAnimation::~RotateAnimation ()
-{
- _transform = 0;
-}
-
-void
-FGAircraftModel::RotateAnimation::init (ssgEntity * object,
- SGPropertyNode * props)
-{
- // Splice in the new transform node
- splice_branch(_transform, object);
- _transform->setName(props->getStringValue("name", 0));
- _prop = fgGetNode(props->getStringValue("property", "/null"), true);
- _offset_deg = props->getDoubleValue("offset-deg", 0.0);
- _factor = props->getDoubleValue("factor", 1.0);
- if (props->hasValue("min-deg")) {
- _has_min = true;
- _min_deg = props->getDoubleValue("min-deg");
- }
- if (props->hasValue("max-deg")) {
- _has_max = true;
- _max_deg = props->getDoubleValue("max-deg");
- }
- _position_deg = props->getDoubleValue("starting-position-deg", 0);
- _center[0] = props->getFloatValue("center/x-m", 0);
- _center[1] = props->getFloatValue("center/y-m", 0);
- _center[2] = props->getFloatValue("center/z-m", 0);
- _axis[0] = props->getFloatValue("axis/x", 0);
- _axis[1] = props->getFloatValue("axis/y", 0);
- _axis[2] = props->getFloatValue("axis/z", 0);
- sgNormalizeVec3(_axis);
-}
-
-void
-FGAircraftModel::RotateAnimation::update (int dt)
-{
- _position_deg = ((_prop->getDoubleValue() + _offset_deg) * _factor);
- if (_has_min && _position_deg < _min_deg)
- _position_deg = _min_deg;
- if (_has_max && _position_deg > _max_deg)
- _position_deg = _max_deg;
- set_rotation(_matrix, _position_deg, _center, _axis);
- _transform->setTransform(_matrix);
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGAircraftModel::TranslateAnimation
-////////////////////////////////////////////////////////////////////////
-
-FGAircraftModel::TranslateAnimation::TranslateAnimation ()
- : _prop(0),
- _offset_m(0.0),
- _factor(1.0),
- _has_min(false),
- _min_m(0.0),
- _has_max(false),
- _max_m(1.0),
- _position_m(0.0),
- _transform(new ssgTransform)
-{
-}
-
-FGAircraftModel::TranslateAnimation::~TranslateAnimation ()
-{
- _transform = 0;
-}
-
-void
-FGAircraftModel::TranslateAnimation::init (ssgEntity * object,
- SGPropertyNode * props)
-{
- // Splice in the new transform node
- splice_branch(_transform, object);
- _transform->setName(props->getStringValue("name", 0));
- _prop = fgGetNode(props->getStringValue("property", "/null"), true);
- _offset_m = props->getDoubleValue("offset-m", 0.0);
- _factor = props->getDoubleValue("factor", 1.0);
- if (props->hasValue("min-m")) {
- _has_min = true;
- _min_m = props->getDoubleValue("min-m");
- }
- if (props->hasValue("max-m")) {
- _has_max = true;
- _max_m = props->getDoubleValue("max-m");
- }
- _position_m = props->getDoubleValue("starting-position-m", 0);
- _axis[0] = props->getFloatValue("axis/x", 0);
- _axis[1] = props->getFloatValue("axis/y", 0);
- _axis[2] = props->getFloatValue("axis/z", 0);
- sgNormalizeVec3(_axis);
-}
-
-void
-FGAircraftModel::TranslateAnimation::update (int dt)
-{
- _position_m = ((_prop->getDoubleValue() + _offset_m) * _factor);
- if (_has_min && _position_m < _min_m)
- _position_m = _min_m;
- if (_has_max && _position_m > _max_m)
- _position_m = _max_m;
- set_translation(_matrix, _position_m, _axis);
- _transform->setTransform(_matrix);
-}
-
-
-// end of model.cxx
+++ /dev/null
-// model.hxx - manage a 3D aircraft model.
-// Written by David Megginson, started 2002.
-//
-// This file is in the Public Domain, and comes with no warranty.
-
-#ifndef __MODEL_HXX
-#define __MODEL_HXX 1
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-#include <string>
-#include <vector>
-
-SG_USING_STD(string);
-SG_USING_STD(vector);
-
-#include "fgfs.hxx"
-#include <simgear/misc/props.hxx>
-#include <simgear/timing/timestamp.hxx>
-
-// Has anyone done anything *really* stupid, like making min and max macros?
-#ifdef min
-#undef min
-#endif
-#ifdef max
-#undef max
-#endif
-
-class FGAircraftModel : public FGSubsystem
-{
-public:
-
- FGAircraftModel ();
- virtual ~FGAircraftModel ();
-
- virtual void init ();
- virtual void bind ();
- virtual void unbind ();
- virtual void update (int dt);
-
-private:
-
- class Animation;
-
- Animation * make_animation (const char * object_name, SGPropertyNode * node);
-
- ssgEntity * _model;
- ssgSelector * _selector;
- ssgTransform * _position;
-
- vector <Animation *> _animations;
-
-
- \f
- //////////////////////////////////////////////////////////////////////
- // Internal classes for individual animations.
- //////////////////////////////////////////////////////////////////////
-
- /**
- * Abstract base class for all animations.
- */
- class Animation
- {
- public:
-
- Animation ();
-
- virtual ~Animation ();
-
- /**
- * Initialize the animation.
- *
- * @param object The object to animate.
- * @param props The property node with configuration information.
- */
- virtual void init (ssgEntity * object, SGPropertyNode * props) = 0;
-
-
- /**
- * Update the animation.
- *
- * @param dt The elapsed time in milliseconds since the last call.
- */
- virtual void update (int dt) = 0;
-
- };
-
-
- /**
- * A no-op animation.
- */
- class NullAnimation : public Animation
- {
- public:
- NullAnimation ();
- virtual ~NullAnimation ();
- virtual void init (ssgEntity * object, SGPropertyNode * props);
- virtual void update (int dt);
- private:
- ssgBranch * _branch;
- };
-
-
- /**
- * Animation to select alternative versions of the same object.
- */
- class SelectAnimation : public Animation
- {
- public:
- SelectAnimation ();
- virtual ~SelectAnimation ();
- virtual void init (ssgEntity * object, SGPropertyNode * props);
- virtual void update (int dt);
- private:
- FGCondition * _condition;
- ssgSelector * _selector;
- };
-
-
- /**
- * Animation to spin an object around a center point.
- *
- * This animation rotates at a specific velocity.
- */
- class SpinAnimation : public Animation
- {
- public:
- SpinAnimation ();
- virtual ~SpinAnimation ();
- virtual void init (ssgEntity * object, SGPropertyNode * props);
- virtual void update (int dt);
- private:
- SGPropertyNode * _prop;
- double _factor;
- double _position_deg;
- sgMat4 _matrix;
- sgVec3 _center;
- sgVec3 _axis;
- ssgTransform * _transform;
- };
-
-
- /**
- * Animation to rotate an object around a center point.
- *
- * This animation rotates to a specific position.
- */
- class RotateAnimation : public Animation
- {
- public:
- RotateAnimation ();
- virtual ~RotateAnimation ();
- virtual void init (ssgEntity * object, SGPropertyNode * props);
- virtual void update (int dt);
- private:
- SGPropertyNode * _prop;
- double _offset_deg;
- double _factor;
- bool _has_min;
- double _min_deg;
- bool _has_max;
- double _max_deg;
- double _position_deg;
- sgMat4 _matrix;
- sgVec3 _center;
- sgVec3 _axis;
- ssgTransform * _transform;
- };
-
-
- /**
- * Animation to slide along an axis.
- */
- class TranslateAnimation : public Animation
- {
- public:
- TranslateAnimation ();
- virtual ~TranslateAnimation ();
- virtual void init (ssgEntity * object, SGPropertyNode * props);
- virtual void update (int dt);
- private:
- SGPropertyNode * _prop;
- double _offset_m;
- double _factor;
- bool _has_min;
- double _min_m;
- bool _has_max;
- double _max_m;
- double _position_m;
- sgMat4 _matrix;
- sgVec3 _axis;
- ssgTransform * _transform;
- };
-
-};
-
-extern FGAircraftModel current_model;
-
-#endif // __MODEL_HXX
-
FDM \
GUI \
Input \
+ Model \
Navaids \
$(NETWORK_DIRS) \
Objects \
--- /dev/null
+.deps
+Makefile
+Makefile.in
--- /dev/null
+noinst_LIBRARIES = libModel.a
+
+libModel_a_SOURCES = model.cxx model.hxx \
+ acmodel.cxx acmodel.hxx
+
+if OLD_AUTOMAKE
+INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src
+else
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
+endif
--- /dev/null
+Last updated $Date$
+
+This directory contains code for loading, positioning, orienting, and
+animating 3D models.
+
+acmodel.cxx
+acmodel.hxx
+ This module defines the FGAircraftModel subsystem, which manages the 3D
+ model representing the aircraft the user is flying.
+
+model.cxx
+model.hxx
+ This module defines the FG3DModel class, which represents any 3D
+ model in the FlightGear world.
--- /dev/null
+// model.cxx - manage a 3D aircraft model.
+// Written by David Megginson, started 2002.
+//
+// This file is in the Public Domain, and comes with no warranty.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> // for strcmp()
+
+#include <plib/sg.h>
+#include <plib/ssg.h>
+
+#include <simgear/compiler.h>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/viewmgr.hxx>
+#include "acmodel.hxx"
+
+extern ssgRoot * cockpit; // FIXME: from main.cxx
+
+FGAircraftModel current_model; // FIXME: add to globals
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGAircraftModel
+////////////////////////////////////////////////////////////////////////
+
+FGAircraftModel::FGAircraftModel ()
+ : _aircraft(0)
+{
+}
+
+FGAircraftModel::~FGAircraftModel ()
+{
+ delete _aircraft;
+}
+
+void
+FGAircraftModel::init ()
+{
+ _aircraft = new FG3DModel;
+ _aircraft->init(fgGetString("/sim/model/path", "Models/Geometry/glider.ac"));
+ cockpit->addKid(_aircraft->getSceneGraph());
+}
+
+void
+FGAircraftModel::bind ()
+{
+ // No-op
+}
+
+void
+FGAircraftModel::unbind ()
+{
+ // No-op
+}
+
+void
+FGAircraftModel::update (int dt)
+{
+ int view_number = globals->get_viewmgr()->get_current();
+
+ if (view_number == 0 && !fgGetBool("/sim/view/internal")) {
+ _aircraft->setVisible(false);
+ return;
+ }
+
+ _aircraft->setVisible(true);
+
+ _aircraft->setPosition(fgGetDouble("/position/longitude-deg"),
+ fgGetDouble("/position/latitude-deg"),
+ fgGetDouble("/position/altitude-ft"));
+ _aircraft->setOrientation(fgGetDouble("/orientation/roll-deg"),
+ fgGetDouble("/orientation/pitch-deg"),
+ fgGetDouble("/orientation/heading-deg"));
+ _aircraft->update(dt);
+}
+
+
+// end of model.cxx
--- /dev/null
+// model.hxx - manage a 3D aircraft model.
+// Written by David Megginson, started 2002.
+//
+// This file is in the Public Domain, and comes with no warranty.
+
+#ifndef __ACMODEL_HXX
+#define __ACMODEL_HXX 1
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <vector>
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+#include <simgear/misc/props.hxx>
+
+#include <Main/fgfs.hxx>
+
+#include "model.hxx"
+
+
+class FGAircraftModel : public FGSubsystem
+{
+public:
+
+ FGAircraftModel ();
+ virtual ~FGAircraftModel ();
+
+ virtual void init ();
+ virtual void bind ();
+ virtual void unbind ();
+ virtual void update (int dt);
+
+private:
+
+ FG3DModel * _aircraft;
+
+};
+
+extern FGAircraftModel current_model;
+
+#endif // __ACMODEL_HXX
+
--- /dev/null
+// model.cxx - manage a 3D aircraft model.
+// Written by David Megginson, started 2002.
+//
+// This file is in the Public Domain, and comes with no warranty.
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> // for strcmp()
+
+#include <plib/sg.h>
+#include <plib/ssg.h>
+
+#include <simgear/compiler.h>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/point3d.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/misc/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+
+#include <Main/globals.hxx>
+#include <Scenery/scenery.hxx>
+
+#include "model.hxx"
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Static utility functions.
+////////////////////////////////////////////////////////////////////////
+
+/**
+ * Locate a named SSG node in a branch.
+ */
+static ssgEntity *
+find_named_node (ssgEntity * node, const char * name)
+{
+ char * node_name = node->getName();
+ if (node_name != 0 && !strcmp(name, node_name))
+ return node;
+ else if (node->isAKindOf(ssgTypeBranch())) {
+ int nKids = node->getNumKids();
+ for (int i = 0; i < nKids; i++) {
+ ssgEntity * result =
+ find_named_node(((ssgBranch*)node)->getKid(i), name);
+ if (result != 0)
+ return result;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Splice a branch in between all child nodes and their parents.
+ */
+static void
+splice_branch (ssgBranch * branch, ssgEntity * child)
+{
+ int nParents = child->getNumParents();
+ branch->addKid(child);
+ for (int i = 0; i < nParents; i++) {
+ ssgBranch * parent = child->getParent(i);
+ parent->replaceKid(child, branch);
+ }
+}
+
+/**
+ * Set up the transform matrix for a spin or rotation.
+ */
+static void
+set_rotation (sgMat4 &matrix, double position_deg,
+ sgVec3 ¢er, sgVec3 &axis)
+{
+ float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
+
+ float s = (float) sin ( temp_angle ) ;
+ float c = (float) cos ( temp_angle ) ;
+ float t = SG_ONE - c ;
+
+ // axis was normalized at load time
+ // hint to the compiler to put these into FP registers
+ float x = axis[0];
+ float y = axis[1];
+ float z = axis[2];
+
+ matrix[0][0] = t * x * x + c ;
+ matrix[0][1] = t * y * x - s * z ;
+ matrix[0][2] = t * z * x + s * y ;
+ matrix[0][3] = SG_ZERO;
+
+ matrix[1][0] = t * x * y + s * z ;
+ matrix[1][1] = t * y * y + c ;
+ matrix[1][2] = t * z * y - s * x ;
+ matrix[1][3] = SG_ZERO;
+
+ matrix[2][0] = t * x * z - s * y ;
+ matrix[2][1] = t * y * z + s * x ;
+ matrix[2][2] = t * z * z + c ;
+ matrix[2][3] = SG_ZERO;
+
+ // hint to the compiler to put these into FP registers
+ x = center[0];
+ y = center[1];
+ z = center[2];
+
+ matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
+ matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
+ matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
+ matrix[3][3] = SG_ONE;
+}
+
+/**
+ * Set up the transform matrix for a translation.
+ */
+static void
+set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
+{
+ sgVec3 xyz;
+ sgScaleVec3(xyz, axis, position_m);
+ sgMakeTransMat4(matrix, xyz);
+}
+
+
+// TODO: once this is working, look at Norm's optimized version
+static void
+world_coordinate( sgCoord *obj_pos,
+ double lat_deg, double lon_deg, double elev_ft,
+ double roll_deg, double pitch_deg, double hdg_deg)
+{
+ Point3D center = scenery.get_center();
+
+ // setup transforms
+ Point3D geod( lon_deg * SGD_DEGREES_TO_RADIANS,
+ lat_deg * SGD_DEGREES_TO_RADIANS,
+ elev_ft * SG_FEET_TO_METER);
+
+ Point3D world_pos = sgGeodToCart( geod );
+ Point3D offset = world_pos - center;
+
+ sgMat4 POS;
+ sgMakeTransMat4( POS, offset.x(), offset.y(), offset.z() );
+
+ sgVec3 obj_bk, obj_rt, obj_up;
+ sgSetVec3( obj_bk, 1.0, 0.0, 0.0); // X axis
+ sgSetVec3( obj_rt, 0.0, 1.0, 0.0); // Y axis
+ sgSetVec3( obj_up, 0.0, 0.0, 1.0); // Z axis
+
+ sgMat4 ROT_lon, ROT_lat, ROT_hdg, ROT_pitch, ROT_roll;
+ sgMakeRotMat4( ROT_lon, lon_deg, obj_up );
+ sgMakeRotMat4( ROT_lat, 90 - lat_deg, obj_rt );
+ sgMakeRotMat4( ROT_hdg, -hdg_deg, obj_up );
+ sgMakeRotMat4( ROT_pitch, pitch_deg, obj_rt );
+ sgMakeRotMat4( ROT_roll, -roll_deg, obj_bk );
+
+ sgMat4 TRANS;
+ sgCopyMat4( TRANS, ROT_roll );
+ sgPostMultMat4( TRANS, ROT_pitch );
+ sgPostMultMat4( TRANS, ROT_hdg );
+ sgPostMultMat4( TRANS, ROT_lat );
+ sgPostMultMat4( TRANS, ROT_lon );
+ sgPostMultMat4( TRANS, POS );
+
+ sgSetCoord( obj_pos, TRANS );
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::FG3DModel ()
+ : _model(0),
+ _selector(new ssgSelector),
+ _position(new ssgTransform)
+{
+}
+
+FG3DModel::~FG3DModel ()
+{
+ // since the nodes are attached to the scene graph, they'll be
+ // deleted automatically
+
+ for (int i = 0; i < _animations.size(); i++) {
+ Animation * tmp = _animations[i];
+ _animations[i] = 0;
+ delete tmp;
+ }
+
+}
+
+void
+FG3DModel::init (const string &path)
+{
+ SGPropertyNode props;
+
+ // Load the 3D aircraft object itself
+ SGPath xmlpath = globals->get_fg_root();
+ SGPath modelpath = path;
+ xmlpath.append(modelpath.str());
+
+ // Check for an XML wrapper
+ if (xmlpath.str().substr(xmlpath.str().size() - 4, 4) == ".xml") {
+ readProperties(xmlpath.str(), &props);
+ if (props.hasValue("/path")) {
+ modelpath = modelpath.dir();
+ modelpath.append(props.getStringValue("/path"));
+ } else {
+ throw sg_exception("No path for model");
+ }
+ }
+
+ // Assume that textures are in
+ // the same location as the XML file.
+ ssgTexturePath((char *)xmlpath.dir().c_str());
+ _model = ssgLoad((char *)modelpath.c_str());
+ if (_model == 0)
+ throw sg_exception("Failed to load 3D model");
+
+ // Load animations
+ vector<SGPropertyNode *> animation_nodes = props.getChildren("animation");
+ for (unsigned int i = 0; i < animation_nodes.size(); i++) {
+ vector<SGPropertyNode *> name_nodes =
+ animation_nodes[i]->getChildren("object-name");
+ if (name_nodes.size() < 1) {
+ SG_LOG(SG_INPUT, SG_ALERT, "No object-name given for transformation");
+ } else {
+ for (unsigned int j = 0; j < name_nodes.size(); j++) {
+ Animation * animation =
+ make_animation(name_nodes[j]->getStringValue(), animation_nodes[i]);
+ if (animation != 0)
+ _animations.push_back(animation);
+ }
+ }
+ }
+
+ // Set up the alignment node
+ ssgTransform * align = new ssgTransform;
+ align->addKid(_model);
+ sgMat4 rot_matrix;
+ sgMat4 off_matrix;
+ sgMat4 res_matrix;
+ float h_rot = props.getFloatValue("/offsets/heading-deg", 0.0);
+ float p_rot = props.getFloatValue("/offsets/roll-deg", 0.0);
+ float r_rot = props.getFloatValue("/offsets/pitch-deg", 0.0);
+ float x_off = props.getFloatValue("/offsets/x-m", 0.0);
+ float y_off = props.getFloatValue("/offsets/y-m", 0.0);
+ float z_off = props.getFloatValue("/offsets/z-m", 0.0);
+ sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
+ sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
+ sgMultMat4(res_matrix, off_matrix, rot_matrix);
+ align->setTransform(res_matrix);
+
+ // Set up the position node
+ _position->addKid(align);
+
+ // Set up the selector node
+ _selector->addKid(_position);
+ _selector->clrTraversalMaskBits(SSGTRAV_HOT);
+}
+
+void
+FG3DModel::update (int dt)
+{
+ for (unsigned int i = 0; i < _animations.size(); i++)
+ _animations[i]->update(dt);
+
+ _selector->select(true);
+
+ sgCoord obj_pos;
+ world_coordinate(&obj_pos, _lat_deg, _lon_deg, _elev_ft,
+ _roll_deg, _pitch_deg, _heading_deg);
+ _position->setTransform(&obj_pos);
+}
+
+bool
+FG3DModel::getVisible () const
+{
+ return _selector->getSelect();
+}
+
+void
+FG3DModel::setVisible (bool visible)
+{
+ _selector->select(visible);
+}
+
+void
+FG3DModel::setPosition (double lon_deg, double lat_deg, double elev_ft)
+{
+ _lon_deg = lon_deg;
+ _lat_deg = lat_deg;
+ _elev_ft = elev_ft;
+}
+
+void
+FG3DModel::setOrientation (double roll_deg, double pitch_deg,
+ double heading_deg)
+{
+ _roll_deg = roll_deg;
+ _pitch_deg = pitch_deg;
+ _heading_deg = heading_deg;
+}
+
+FG3DModel::Animation *
+FG3DModel::make_animation (const char * object_name,
+ SGPropertyNode * node)
+{
+ Animation * animation = 0;
+ const char * type = node->getStringValue("type");
+ if (!strcmp("none", type)) {
+ animation = new NullAnimation();
+ } else if (!strcmp("select", type)) {
+ animation = new SelectAnimation();
+ } else if (!strcmp("spin", type)) {
+ animation = new SpinAnimation();
+ } else if (!strcmp("rotate", type)) {
+ animation = new RotateAnimation();
+ } else if (!strcmp("translate", type)) {
+ animation = new TranslateAnimation();
+ } else {
+ animation = new NullAnimation();
+ SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
+ }
+
+ ssgEntity * object = find_named_node(_model, object_name);
+ if (object == 0) {
+ SG_LOG(SG_INPUT, SG_WARN, "Object " << object_name << " not found");
+ delete animation;
+ animation = 0;
+ } else {
+ animation->init(object, node);
+ }
+
+ return animation;
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::Animation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::Animation::Animation ()
+{
+}
+
+FG3DModel::Animation::~Animation ()
+{
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::NullAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::NullAnimation::NullAnimation ()
+ : _branch(new ssgBranch)
+{
+}
+
+FG3DModel::NullAnimation::~NullAnimation ()
+{
+ _branch = 0;
+}
+
+void
+FG3DModel::NullAnimation::init (ssgEntity * object,
+ SGPropertyNode * props)
+{
+ splice_branch(_branch, object);
+ _branch->setName(props->getStringValue("name", 0));
+}
+
+void
+FG3DModel::NullAnimation::update (int dt)
+{
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::SelectAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::SelectAnimation::SelectAnimation ()
+ : _condition(0),
+ _selector(new ssgSelector)
+{
+}
+
+FG3DModel::SelectAnimation::~SelectAnimation ()
+{
+ delete _condition;
+ _selector = 0;
+}
+
+void
+FG3DModel::SelectAnimation::init (ssgEntity * object,
+ SGPropertyNode * props)
+{
+ splice_branch(_selector, object);
+ _selector->setName(props->getStringValue("name", 0));
+ SGPropertyNode * node = props->getChild("condition");
+ if (node != 0) {
+ _condition = fgReadCondition(node);
+ }
+}
+
+void
+FG3DModel::SelectAnimation::update (int dt)
+{
+ if (_condition != 0 && _condition->test())
+ _selector->select(0xffff);
+ else
+ _selector->select(0x0000);
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::SpinAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::SpinAnimation::SpinAnimation ()
+ : _prop(0),
+ _factor(0),
+ _position_deg(0),
+ _transform(new ssgTransform)
+{
+}
+
+FG3DModel::SpinAnimation::~SpinAnimation ()
+{
+ _transform = 0;
+}
+
+void
+FG3DModel::SpinAnimation::init (ssgEntity * object,
+ SGPropertyNode * props)
+{
+ // Splice in the new transform node
+ splice_branch(_transform, object);
+ _transform->setName(props->getStringValue("name", 0));
+ _prop = fgGetNode(props->getStringValue("property", "/null"), true);
+ _factor = props->getDoubleValue("factor", 1.0);
+ _position_deg = props->getDoubleValue("starting-position-deg", 0);
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 0);
+ sgNormalizeVec3(_axis);
+}
+
+void
+FG3DModel::SpinAnimation::update (int dt)
+{
+ float velocity_rpms = (_prop->getDoubleValue() * _factor / 60000.0);
+ _position_deg += (dt * velocity_rpms * 360);
+ while (_position_deg < 0)
+ _position_deg += 360.0;
+ while (_position_deg >= 360.0)
+ _position_deg -= 360.0;
+ set_rotation(_matrix, _position_deg, _center, _axis);
+ _transform->setTransform(_matrix);
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::RotateAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::RotateAnimation::RotateAnimation ()
+ : _prop(0),
+ _offset_deg(0.0),
+ _factor(1.0),
+ _has_min(false),
+ _min_deg(0.0),
+ _has_max(false),
+ _max_deg(1.0),
+ _position_deg(0.0),
+ _transform(new ssgTransform)
+{
+}
+
+FG3DModel::RotateAnimation::~RotateAnimation ()
+{
+ _transform = 0;
+}
+
+void
+FG3DModel::RotateAnimation::init (ssgEntity * object,
+ SGPropertyNode * props)
+{
+ // Splice in the new transform node
+ splice_branch(_transform, object);
+ _transform->setName(props->getStringValue("name", 0));
+ _prop = fgGetNode(props->getStringValue("property", "/null"), true);
+ _offset_deg = props->getDoubleValue("offset-deg", 0.0);
+ _factor = props->getDoubleValue("factor", 1.0);
+ if (props->hasValue("min-deg")) {
+ _has_min = true;
+ _min_deg = props->getDoubleValue("min-deg");
+ }
+ if (props->hasValue("max-deg")) {
+ _has_max = true;
+ _max_deg = props->getDoubleValue("max-deg");
+ }
+ _position_deg = props->getDoubleValue("starting-position-deg", 0);
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 0);
+ sgNormalizeVec3(_axis);
+}
+
+void
+FG3DModel::RotateAnimation::update (int dt)
+{
+ _position_deg = ((_prop->getDoubleValue() + _offset_deg) * _factor);
+ if (_has_min && _position_deg < _min_deg)
+ _position_deg = _min_deg;
+ if (_has_max && _position_deg > _max_deg)
+ _position_deg = _max_deg;
+ set_rotation(_matrix, _position_deg, _center, _axis);
+ _transform->setTransform(_matrix);
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::TranslateAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::TranslateAnimation::TranslateAnimation ()
+ : _prop(0),
+ _offset_m(0.0),
+ _factor(1.0),
+ _has_min(false),
+ _min_m(0.0),
+ _has_max(false),
+ _max_m(1.0),
+ _position_m(0.0),
+ _transform(new ssgTransform)
+{
+}
+
+FG3DModel::TranslateAnimation::~TranslateAnimation ()
+{
+ _transform = 0;
+}
+
+void
+FG3DModel::TranslateAnimation::init (ssgEntity * object,
+ SGPropertyNode * props)
+{
+ // Splice in the new transform node
+ splice_branch(_transform, object);
+ _transform->setName(props->getStringValue("name", 0));
+ _prop = fgGetNode(props->getStringValue("property", "/null"), true);
+ _offset_m = props->getDoubleValue("offset-m", 0.0);
+ _factor = props->getDoubleValue("factor", 1.0);
+ if (props->hasValue("min-m")) {
+ _has_min = true;
+ _min_m = props->getDoubleValue("min-m");
+ }
+ if (props->hasValue("max-m")) {
+ _has_max = true;
+ _max_m = props->getDoubleValue("max-m");
+ }
+ _position_m = props->getDoubleValue("starting-position-m", 0);
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 0);
+ sgNormalizeVec3(_axis);
+}
+
+void
+FG3DModel::TranslateAnimation::update (int dt)
+{
+ _position_m = ((_prop->getDoubleValue() + _offset_m) * _factor);
+ if (_has_min && _position_m < _min_m)
+ _position_m = _min_m;
+ if (_has_max && _position_m > _max_m)
+ _position_m = _max_m;
+ set_translation(_matrix, _position_m, _axis);
+ _transform->setTransform(_matrix);
+}
+
+
+// end of model.cxx
--- /dev/null
+// model.hxx - manage a 3D aircraft model.
+// Written by David Megginson, started 2002.
+//
+// This file is in the Public Domain, and comes with no warranty.
+
+#ifndef __MODEL_HXX
+#define __MODEL_HXX 1
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <vector>
+
+SG_USING_STD(vector);
+
+#include <Main/fg_props.hxx>
+
+// Has anyone done anything *really* stupid, like making min and max macros?
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+
+class FG3DModel
+{
+public:
+
+ FG3DModel ();
+ virtual ~FG3DModel ();
+
+ virtual void init (const string &path);
+ virtual void update (int dt);
+
+ virtual bool getVisible () const;
+ virtual void setVisible (bool visible);
+
+ virtual double getLongitudeDeg () const { return _lon_deg; }
+ virtual double getLatitudeDeg () const { return _lat_deg; }
+ virtual double getElevationFt () const { return _elev_ft; }
+
+ virtual void setPosition (double lon_deg, double lat_deg, double elev_ft);
+
+ virtual double getRoll () const { return _roll_deg; }
+ virtual double getPitch () const { return _pitch_deg; }
+ virtual double getHeading () const { return _heading_deg; }
+
+ virtual void setOrientation (double roll_deg, double pitch_deg,
+ double heading_deg);
+
+ virtual ssgEntity * getSceneGraph () const { return _selector; }
+
+private:
+
+ class Animation;
+ Animation * make_animation (const char * object_name, SGPropertyNode * node);
+
+ // Geodetic position
+ double _lon_deg;
+ double _lat_deg;
+ double _elev_ft;
+
+ // Orientation
+ double _roll_deg;
+ double _pitch_deg;
+ double _heading_deg;
+
+ // Animations
+
+ vector <Animation *> _animations;
+
+
+ // Scene graph
+ ssgEntity * _model;
+ ssgSelector * _selector;
+ ssgTransform * _position;
+
+
+ \f
+ //////////////////////////////////////////////////////////////////////
+ // Internal classes for individual animations.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Abstract base class for all animations.
+ */
+ class Animation
+ {
+ public:
+
+ Animation ();
+
+ virtual ~Animation ();
+
+ /**
+ * Initialize the animation.
+ *
+ * @param object The object to animate.
+ * @param props The property node with configuration information.
+ */
+ virtual void init (ssgEntity * object, SGPropertyNode * props) = 0;
+
+
+ /**
+ * Update the animation.
+ *
+ * @param dt The elapsed time in milliseconds since the last call.
+ */
+ virtual void update (int dt) = 0;
+
+ };
+
+
+ /**
+ * A no-op animation.
+ */
+ class NullAnimation : public Animation
+ {
+ public:
+ NullAnimation ();
+ virtual ~NullAnimation ();
+ virtual void init (ssgEntity * object, SGPropertyNode * props);
+ virtual void update (int dt);
+ private:
+ ssgBranch * _branch;
+ };
+
+
+ /**
+ * Animation to select alternative versions of the same object.
+ */
+ class SelectAnimation : public Animation
+ {
+ public:
+ SelectAnimation ();
+ virtual ~SelectAnimation ();
+ virtual void init (ssgEntity * object, SGPropertyNode * props);
+ virtual void update (int dt);
+ private:
+ FGCondition * _condition;
+ ssgSelector * _selector;
+ };
+
+
+ /**
+ * Animation to spin an object around a center point.
+ *
+ * This animation rotates at a specific velocity.
+ */
+ class SpinAnimation : public Animation
+ {
+ public:
+ SpinAnimation ();
+ virtual ~SpinAnimation ();
+ virtual void init (ssgEntity * object, SGPropertyNode * props);
+ virtual void update (int dt);
+ private:
+ SGPropertyNode * _prop;
+ double _factor;
+ double _position_deg;
+ sgMat4 _matrix;
+ sgVec3 _center;
+ sgVec3 _axis;
+ ssgTransform * _transform;
+ };
+
+
+ /**
+ * Animation to rotate an object around a center point.
+ *
+ * This animation rotates to a specific position.
+ */
+ class RotateAnimation : public Animation
+ {
+ public:
+ RotateAnimation ();
+ virtual ~RotateAnimation ();
+ virtual void init (ssgEntity * object, SGPropertyNode * props);
+ virtual void update (int dt);
+ private:
+ SGPropertyNode * _prop;
+ double _offset_deg;
+ double _factor;
+ bool _has_min;
+ double _min_deg;
+ bool _has_max;
+ double _max_deg;
+ double _position_deg;
+ sgMat4 _matrix;
+ sgVec3 _center;
+ sgVec3 _axis;
+ ssgTransform * _transform;
+ };
+
+
+ /**
+ * Animation to slide along an axis.
+ */
+ class TranslateAnimation : public Animation
+ {
+ public:
+ TranslateAnimation ();
+ virtual ~TranslateAnimation ();
+ virtual void init (ssgEntity * object, SGPropertyNode * props);
+ virtual void update (int dt);
+ private:
+ SGPropertyNode * _prop;
+ double _offset_m;
+ double _factor;
+ bool _has_min;
+ double _min_m;
+ bool _has_max;
+ double _max_m;
+ double _position_m;
+ sgMat4 _matrix;
+ sgVec3 _axis;
+ ssgTransform * _transform;
+ };
+
+};
+
+#endif // __MODEL_HXX
+