]> git.mxchange.org Git - flightgear.git/commitdiff
Moved FGAircraftModel subsystem out into its own directory, and
authordavid <david>
Fri, 5 Apr 2002 03:19:34 +0000 (03:19 +0000)
committerdavid <david>
Fri, 5 Apr 2002 03:19:34 +0000 (03:19 +0000)
separated out a new class, FG3DModel, that allows any arbitrary 3D
model to be positioned, oriented, and animated (not just the
aircraft).

13 files changed:
src/Main/Makefile.am
src/Main/README
src/Main/main.cxx
src/Main/model.cxx [deleted file]
src/Main/model.hxx [deleted file]
src/Makefile.am
src/Model/.cvsignore [new file with mode: 0644]
src/Model/Makefile.am [new file with mode: 0644]
src/Model/README [new file with mode: 0644]
src/Model/acmodel.cxx [new file with mode: 0644]
src/Model/acmodel.hxx [new file with mode: 0644]
src/Model/model.cxx [new file with mode: 0644]
src/Model/model.hxx [new file with mode: 0644]

index 84feff63bfac4aa18e31fd1c6cf92491bfc948a8..a3056b5a7da82bc68325e37dfb5d796ef605319c 100644 (file)
@@ -48,7 +48,6 @@ fgfs_SOURCES = \
         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 \
@@ -68,6 +67,7 @@ fgfs_LDADD = \
        $(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 \
index 7c4b3cd8feb760ab401f71619ec89434c6ed5df9..b78bb9cc575cc21d1f4ac8ac3d7244e9111b1e56 100644 (file)
@@ -61,11 +61,6 @@ main.cxx
   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
index 2a1cdcf645870bbe066dbc2f8a541a36ce4286b9..68c80e025bcd0a9399fedf0d69e8bab49734b5c0 100644 (file)
@@ -96,6 +96,7 @@ SG_USING_STD(endl);
 
 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
 #include <GUI/gui.h>
+#include <Model/acmodel.hxx>
 #ifdef FG_NETWORK_OLK
 #include <NetworkOLK/network.h>
 #endif
@@ -163,7 +164,6 @@ float scene_farplane = 120000.0f;
 #include "viewmgr.hxx"
 #include "options.hxx"
 #include "logger.hxx"
-#include "model.hxx"
 
 #ifdef macintosh
 #  include <console.h>         // -dw- for command line dialog
diff --git a/src/Main/model.cxx b/src/Main/model.cxx
deleted file mode 100644 (file)
index 461c5a8..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-// 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 &center, 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
diff --git a/src/Main/model.hxx b/src/Main/model.hxx
deleted file mode 100644 (file)
index 439f6ee..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-// 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
-
index d1a55d76f51f7e7b89a924870782c71c9e0e7837..86c9491f019f92e864d3189d447cd773dad834bc 100644 (file)
@@ -21,6 +21,7 @@ SUBDIRS = \
         FDM \
         GUI \
        Input \
+        Model \
        Navaids \
         $(NETWORK_DIRS) \
         Objects \
diff --git a/src/Model/.cvsignore b/src/Model/.cvsignore
new file mode 100644 (file)
index 0000000..e995588
--- /dev/null
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/src/Model/Makefile.am b/src/Model/Makefile.am
new file mode 100644 (file)
index 0000000..ddb86d8
--- /dev/null
@@ -0,0 +1,10 @@
+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
diff --git a/src/Model/README b/src/Model/README
new file mode 100644 (file)
index 0000000..3d21a51
--- /dev/null
@@ -0,0 +1,14 @@
+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.
diff --git a/src/Model/acmodel.cxx b/src/Model/acmodel.cxx
new file mode 100644 (file)
index 0000000..ece3d50
--- /dev/null
@@ -0,0 +1,87 @@
+// 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
diff --git a/src/Model/acmodel.hxx b/src/Model/acmodel.hxx
new file mode 100644 (file)
index 0000000..920fbbd
--- /dev/null
@@ -0,0 +1,46 @@
+// 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
+
diff --git a/src/Model/model.cxx b/src/Model/model.cxx
new file mode 100644 (file)
index 0000000..33f16ce
--- /dev/null
@@ -0,0 +1,598 @@
+// 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 &center, 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
diff --git a/src/Model/model.hxx b/src/Model/model.hxx
new file mode 100644 (file)
index 0000000..08aa4ba
--- /dev/null
@@ -0,0 +1,225 @@
+// 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
+