]> git.mxchange.org Git - flightgear.git/blobdiff - src/Model/model.cxx
Mac OS X fixes and MSVC warning fixes from Jonathan Polley.
[flightgear.git] / src / Model / model.cxx
index f5d5426f55ea8718d153e941e77c7b4571776257..08738012846d94de4bfb247159129b1f5b25373e 100644 (file)
@@ -7,19 +7,22 @@
 #  include <config.h>
 #endif
 
-#include <string.h>            // for strcmp()
+#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/interpolater.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/fg_props.hxx>
 #include <Main/globals.hxx>
+#include <Main/location.hxx>
 #include <Scenery/scenery.hxx>
 
 #include "model.hxx"
@@ -43,9 +46,9 @@ find_named_node (ssgEntity * node, const char * name)
     int nKids = node->getNumKids();
     for (int i = 0; i < nKids; i++) {
       ssgEntity * result =
-       find_named_node(((ssgBranch*)node)->getKid(i), name);
+        find_named_node(((ssgBranch*)node)->getKid(i), name);
       if (result != 0)
-       return result;
+        return result;
     }
   } 
   return 0;
@@ -70,7 +73,7 @@ splice_branch (ssgBranch * branch, ssgEntity * child)
  */
 static void
 set_rotation (sgMat4 &matrix, double position_deg,
-             sgVec3 &center, sgVec3 &axis)
+              sgVec3 &center, sgVec3 &axis)
 {
  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
  
@@ -122,58 +125,23 @@ set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
 }
 
 
-// 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)
-{
-  // setup translation
-  double sea_level_radius_m;
-  double lat_geoc_rad;
-
-  // Convert from geodetic to geocentric
-  // coordinates.
-  sgGeodToGeoc(lat_deg * SGD_DEGREES_TO_RADIANS,
-              elev_ft * SG_FEET_TO_METER,
-              &sea_level_radius_m,
-              &lat_geoc_rad);
-
-  Point3D center = scenery.get_center();
-
-  Point3D geod = Point3D(lon_deg * SG_DEGREES_TO_RADIANS,
-                        lat_geoc_rad,
-                        sea_level_radius_m);
-  geod.setz(geod.radius() + elev_ft * SG_FEET_TO_METER);
-       
-  Point3D world_pos = sgPolarToCart3d( geod );
-  Point3D offset = world_pos - center;
-       
-  sgMat4 POS;
-  sgMakeTransMat4( POS, offset.x(), offset.y(), offset.z() );
-
-  // setup transforms
-  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 );
+/**
+ * Read an interpolation table from properties.
+ */
+static SGInterpTable *
+read_interpolation_table (const SGPropertyNode * props)
+{
+  const SGPropertyNode * table_node = props->getNode("interpolation");
+  if (table_node != 0) {
+    SGInterpTable * table = new SGInterpTable();
+    vector<const SGPropertyNode *> entries = table_node->getChildren("entry");
+    for (int i = 0; i < entries.size(); i++)
+      table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
+                     entries[i]->getDoubleValue("dep", 0.0));
+    return table;
+  } else {
+    return 0;
+  }
 }
 
 
@@ -194,12 +162,9 @@ 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;
-  }
-
+  int i;
+  for (i = 0; i < _animations.size(); i++)
+    delete _animations[i];
 }
 
 void 
@@ -207,12 +172,12 @@ FG3DModel::init (const string &path)
 {
   SGPropertyNode props;
 
-                               // Load the 3D aircraft object itself
+                                // Load the 3D aircraft object itself
   SGPath xmlpath = globals->get_fg_root();
   SGPath modelpath = path;
   xmlpath.append(modelpath.str());
 
-                               // Check for an XML wrapper
+                                // Check for an XML wrapper
   if (xmlpath.str().substr(xmlpath.str().size() - 4, 4) == ".xml") {
     readProperties(xmlpath.str(), &props);
     if (props.hasValue("/path")) {
@@ -223,31 +188,14 @@ FG3DModel::init (const string &path)
     }
   }
 
-                               // Assume that textures are in
-                               // the same location as the XML file.
+                                // Assume that textures are in
+                                // the same location as the XML file.
   ssgTexturePath((char *)xmlpath.dir().c_str());
-  _model = ssgLoad((char *)modelpath.c_str());
+  _model = (ssgBranch *)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
+                                // Set up the alignment node
   ssgTransform * align = new ssgTransform;
   align->addKid(_model);
   sgMat4 rot_matrix;
@@ -264,32 +212,65 @@ FG3DModel::init (const string &path)
   sgMultMat4(res_matrix, off_matrix, rot_matrix);
   align->setTransform(res_matrix);
 
-                               // Set up the position node
+                                // Set up the position node
   _position->addKid(align);
 
-                               // Set up the selector node
+                                // Set up the selector node
   _selector->addKid(_position);
   _selector->clrTraversalMaskBits(SSGTRAV_HOT);
+
+                                // Set up a location class
+  _location = (FGLocation *) new FGLocation;
+
+                                // Load animations
+  vector<SGPropertyNode *> animation_nodes = props.getChildren("animation");
+  unsigned int i;
+  for (i = 0; i < animation_nodes.size(); i++) {
+    vector<SGPropertyNode *> name_nodes =
+      animation_nodes[i]->getChildren("object-name");
+    if (name_nodes.size() < 1) {
+      Animation * animation = make_animation(0, animation_nodes[i]);
+    } 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);
+      }
+    }
+  }
 }
 
 void
 FG3DModel::update (int dt)
 {
-  for (unsigned int i = 0; i < _animations.size(); i++)
+  unsigned int i;
+
+  for (i = 0; i < _animations.size(); i++)
     _animations[i]->update(dt);
 
-  _selector->select(true);
+  _location->setPosition( _lon_deg, _lat_deg, _elev_ft );
+  _location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
 
-  sgCoord obj_pos;
-  world_coordinate(&obj_pos, _lat_deg, _lon_deg, _elev_ft,
-                  _roll_deg, _pitch_deg, _heading_deg);
-  _position->setTransform(&obj_pos);
+  sgMat4 POS;
+  sgCopyMat4(POS, _location->getTransformMatrix());
+  
+  sgVec3 trans;
+  sgCopyVec3(trans, _location->get_view_pos());
+
+  for(i = 0; i < 4; i++) {
+    float tmp = POS[i][3];
+    for( int j=0; j<3; j++ ) {
+      POS[i][j] += (tmp * trans[j]);
+    }
+  }
+  _position->setTransform(POS);
 }
 
 bool
 FG3DModel::getVisible () const
 {
-  return _selector->getSelect();
+  return (_selector->getSelect() != 0);
 }
 
 void
@@ -298,6 +279,24 @@ FG3DModel::setVisible (bool visible)
   _selector->select(visible);
 }
 
+void
+FG3DModel::setLongitudeDeg (double lon_deg)
+{
+  _lon_deg = lon_deg;
+}
+
+void
+FG3DModel::setLatitudeDeg (double lat_deg)
+{
+  _lat_deg = lat_deg;
+}
+
+void
+FG3DModel::setElevationFt (double elev_ft)
+{
+  _elev_ft = elev_ft;
+}
+
 void
 FG3DModel::setPosition (double lon_deg, double lat_deg, double elev_ft)
 {
@@ -306,9 +305,27 @@ FG3DModel::setPosition (double lon_deg, double lat_deg, double elev_ft)
   _elev_ft = elev_ft;
 }
 
+void
+FG3DModel::setRollDeg (double roll_deg)
+{
+  _roll_deg = roll_deg;
+}
+
+void
+FG3DModel::setPitchDeg (double pitch_deg)
+{
+  _pitch_deg = pitch_deg;
+}
+
+void
+FG3DModel::setHeadingDeg (double heading_deg)
+{
+  _heading_deg = heading_deg;
+}
+
 void
 FG3DModel::setOrientation (double roll_deg, double pitch_deg,
-                          double heading_deg)
+                           double heading_deg)
 {
   _roll_deg = roll_deg;
   _pitch_deg = pitch_deg;
@@ -317,12 +334,16 @@ FG3DModel::setOrientation (double roll_deg, double pitch_deg,
 
 FG3DModel::Animation *
 FG3DModel::make_animation (const char * object_name,
-                                SGPropertyNode * node)
+                          SGPropertyNode * node)
 {
   Animation * animation = 0;
   const char * type = node->getStringValue("type");
   if (!strcmp("none", type)) {
     animation = new NullAnimation();
+  } else if (!strcmp("range", type)) {
+    animation = new RangeAnimation();
+  } else if (!strcmp("billboard", type)) {
+    animation = new BillboardAnimation();
   } else if (!strcmp("select", type)) {
     animation = new SelectAnimation();
   } else if (!strcmp("spin", type)) {
@@ -336,15 +357,19 @@ FG3DModel::make_animation (const char * object_name,
     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;
+  ssgEntity * object;
+  if (object_name != 0) {
+    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);
+    object = _model;
   }
 
+  animation->init(object, node);
   return animation;
 }
 
@@ -380,7 +405,7 @@ FG3DModel::NullAnimation::~NullAnimation ()
 
 void
 FG3DModel::NullAnimation::init (ssgEntity * object,
-                                     SGPropertyNode * props)
+                                      SGPropertyNode * props)
 {
   splice_branch(_branch, object);
   _branch->setName(props->getStringValue("name", 0));
@@ -392,6 +417,71 @@ FG3DModel::NullAnimation::update (int dt)
 }
 
 
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::RangeAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::RangeAnimation::RangeAnimation ()
+  : _branch(new ssgRangeSelector)
+{
+}
+
+FG3DModel::RangeAnimation::~RangeAnimation ()
+{
+  _branch = 0;
+}
+
+void
+FG3DModel::RangeAnimation::init (ssgEntity * object,
+                                      SGPropertyNode * props)
+{
+  float ranges[2];
+  splice_branch(_branch, object);
+  _branch->setName(props->getStringValue("name", 0));
+  ranges[0] = props->getFloatValue("min-m", 0);
+  ranges[1] = props->getFloatValue("max-m", 5000);
+  _branch->setRanges(ranges, 2);
+}
+
+void
+FG3DModel::RangeAnimation::update (int dt)
+{
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FG3DModel::BillboardAnimation
+////////////////////////////////////////////////////////////////////////
+
+FG3DModel::BillboardAnimation::BillboardAnimation ()
+  : _branch(0)
+{
+  // Note: we cannot allocate the branch until we know whether
+  // it can rotate around the x axis as well as the z axis.
+}
+
+FG3DModel::BillboardAnimation::~BillboardAnimation ()
+{
+  _branch = 0;
+}
+
+void
+FG3DModel::BillboardAnimation::init (ssgEntity * object,
+                                    SGPropertyNode * props)
+{
+  _branch = new ssgCutout(props->getBoolValue("spherical", true));
+  splice_branch(_branch, object);
+  _branch->setName(props->getStringValue("name", 0));
+}
+
+void
+FG3DModel::BillboardAnimation::update (int dt)
+{
+}
+
+
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of FG3DModel::SelectAnimation
@@ -411,7 +501,7 @@ FG3DModel::SelectAnimation::~SelectAnimation ()
 
 void
 FG3DModel::SelectAnimation::init (ssgEntity * object,
-                                     SGPropertyNode * props)
+                                      SGPropertyNode * props)
 {
   splice_branch(_selector, object);
   _selector->setName(props->getStringValue("name", 0));
@@ -451,9 +541,9 @@ FG3DModel::SpinAnimation::~SpinAnimation ()
 
 void
 FG3DModel::SpinAnimation::init (ssgEntity * object,
-                                     SGPropertyNode * props)
+                                      SGPropertyNode * props)
 {
-                               // Splice in the new transform node
+                                // Splice in the new transform node
   splice_branch(_transform, object);
   _transform->setName(props->getStringValue("name", 0));
   _prop = fgGetNode(props->getStringValue("property", "/null"), true);
@@ -491,6 +581,7 @@ FG3DModel::RotateAnimation::RotateAnimation ()
   : _prop(0),
     _offset_deg(0.0),
     _factor(1.0),
+    _table(0),
     _has_min(false),
     _min_deg(0.0),
     _has_max(false),
@@ -502,19 +593,21 @@ FG3DModel::RotateAnimation::RotateAnimation ()
 
 FG3DModel::RotateAnimation::~RotateAnimation ()
 {
+  delete _table;
   _transform = 0;
 }
 
 void
 FG3DModel::RotateAnimation::init (ssgEntity * object,
-                                       SGPropertyNode * props)
+                                 SGPropertyNode * props)
 {
-                               // Splice in the new transform node
+                                // 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);
+  _table = read_interpolation_table(props);
   if (props->hasValue("min-deg")) {
     _has_min = true;
     _min_deg = props->getDoubleValue("min-deg");
@@ -536,11 +629,15 @@ FG3DModel::RotateAnimation::init (ssgEntity * object,
 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;
+  if (_table == 0) {
+    _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;
+  } else {
+    _position_deg = _table->interpolate(_prop->getDoubleValue());
+  }
   set_rotation(_matrix, _position_deg, _center, _axis);
   _transform->setTransform(_matrix);
 }
@@ -555,6 +652,7 @@ FG3DModel::TranslateAnimation::TranslateAnimation ()
   : _prop(0),
     _offset_m(0.0),
     _factor(1.0),
+    _table(0),
     _has_min(false),
     _min_m(0.0),
     _has_max(false),
@@ -566,19 +664,21 @@ FG3DModel::TranslateAnimation::TranslateAnimation ()
 
 FG3DModel::TranslateAnimation::~TranslateAnimation ()
 {
+  delete _table;
   _transform = 0;
 }
 
 void
 FG3DModel::TranslateAnimation::init (ssgEntity * object,
-                                       SGPropertyNode * props)
+                                    SGPropertyNode * props)
 {
-                               // Splice in the new transform node
+                                // 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);
+  _table = read_interpolation_table(props);
   if (props->hasValue("min-m")) {
     _has_min = true;
     _min_m = props->getDoubleValue("min-m");
@@ -597,11 +697,15 @@ FG3DModel::TranslateAnimation::init (ssgEntity * object,
 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;
+  if (_table == 0) {
+    _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;
+  } else {
+    _position_m = _table->interpolate(_prop->getDoubleValue());
+  }
   set_translation(_matrix, _position_m, _axis);
   _transform->setTransform(_matrix);
 }