]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/model.cxx
Somewhere along the line in the recent changes some std::cout were
[flightgear.git] / src / Main / model.cxx
index 5d20a357bf11098cd117671ac3ac4729ea35c206..8016f97ca3b6e5da9ac240e6d5158405ad210257 100644 (file)
@@ -46,17 +46,14 @@ find_named_node (ssgEntity * node, const string &name)
 }
 
 FGAircraftModel::FGAircraftModel ()
-  : _props(new SGPropertyNode),
-    _object(0),
+  : _model(0),
     _selector(new ssgSelector),
-    _position(new ssgTransform),
-    _prop_position(0)
+    _position(new ssgTransform)
 {
 }
 
 FGAircraftModel::~FGAircraftModel ()
 {
-  delete _props;
   // since the nodes are attached to the scene graph, they'll be
   // deleted automatically
 }
@@ -67,15 +64,19 @@ 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
   SGPath path = globals->get_fg_root();
   path.append(fgGetString("/sim/model/path", "Models/Geometry/glider.ac"));
 
   if (path.str().substr(path.str().size() - 4, 4) == ".xml") {
-    readProperties(path.str(), _props);
-    if (_props->hasValue("/path")) {
+    readProperties(path.str(), &props);
+    if (props.hasValue("/path")) {
       path = path.dir();;
-      path.append(_props->getStringValue("/path"));
+      path.append(props.getStringValue("/path"));
     } else {
       path = globals->get_fg_root();
       path.append("Models/Geometry/glider.ac");
@@ -83,37 +84,41 @@ FGAircraftModel::init ()
   }
 
   ssgTexturePath((char *)path.dir().c_str());
-  _object = ssgLoad((char *)path.c_str());
-  if (_object == 0) {
-    _object = ssgLoad((char *)"Models/Geometry/glider.ac");
-    if (_object == 0)
+  _model = ssgLoad((char *)path.c_str());
+  if (_model == 0) {
+    _model = ssgLoad((char *)"Models/Geometry/glider.ac");
+    if (_model == 0)
       throw sg_exception("Failed to load an aircraft model");
   }
 
-                               // Find the propeller
-  ssgEntity * prop_node = find_named_node(_object, "Propeller");
-  if (prop_node != 0) {
-    _prop_position = new ssgTransform;
-    int nParents = prop_node->getNumParents();
-    _prop_position->addKid(prop_node);
-    for (int i = 0; i < nParents; i++) {
-      ssgBranch * parent = prop_node->getParent(i);
-      parent->replaceKid(prop_node, _prop_position);
+                               // 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++) {
+       _animations.push_back(read_animation(name_nodes[j]->getStringValue(),
+                                            animation_nodes[i]));
+      }
     }
   }
 
                                // Set up the alignment node
   ssgTransform * align = new ssgTransform;
-  align->addKid(_object);
+  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);
+  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);
@@ -141,23 +146,18 @@ FGAircraftModel::unbind ()
 void
 FGAircraftModel::update (int dt)
 {
-  // START TEMPORARY KLUDGE
-  static float prop_rotation = 0;
-  static sgMat4 prop_matrix;
-
   _current_timestamp.stamp();
-  long ms = (_current_timestamp - _last_timestamp) / 1000;
+  long elapsed_ms = (_current_timestamp - _last_timestamp) / 1000;
   _last_timestamp.stamp();
 
-  double rpms = fgGetDouble("/engines/engine[0]/rpm") / 60000.0;
-  prop_rotation += (ms * rpms * 360);
-  while (prop_rotation >= 360)
-    prop_rotation -= 360;
-  // END TEMPORARY KLUDGE
+  int view_number = globals->get_viewmgr()->get_current();
 
-  if (globals->get_viewmgr()->get_current() == 0) {
+  if (view_number == 0 && !fgGetBool("/sim/view/internal")) {
     _selector->select(false);
   } else {
+    for (unsigned int i = 0; i < _animations.size(); i++)
+      do_animation(_animations[i], elapsed_ms);
+
     _selector->select(true);
     FGViewerRPH *pilot_view =
       (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
@@ -173,26 +173,213 @@ FGAircraftModel::update (int dt)
     
     sgMat4 sgTUX;
     sgCopyMat4( sgTUX, sgROT );
-    sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
-    sgPostMultMat4( sgTUX, sgTRANS );
-    
+    sgMat4 VIEW_ROT;
+    sgCopyMat4( VIEW_ROT, pilot_view->get_VIEW_ROT());
+    if (view_number == 0) {
+                               // FIXME: orientation is not applied
+                               // correctly when view is not forward
+      sgMakeRotMat4( sgROT, -pilot_view->get_view_offset()
+                    * SGD_RADIANS_TO_DEGREES, pilot_view->get_world_up() );
+
+      /* Warning lame hack from Wilson ahead */
+      /* get the pitch value */
+      sgVec3 rph;
+      sgCopyVec3(rph, pilot_view->get_rph());
+      /* double it to counter the value already in the VIEW_ROT */
+      float pitch = rph[1] * 2;
+      /* make a ROT matrix 
+         with the values waited by the X coordinate from the offset 
+         rotation see sgROT above
+      */
+      sgMat4 PunROT;
+      PunROT[0][0] = SG_ONE;
+      PunROT[0][1] = SG_ZERO;
+      PunROT[0][2] = SG_ZERO;
+      PunROT[0][3] = SG_ZERO;
+      PunROT[1][0] = SG_ZERO;
+      PunROT[1][1] = cos((1 - sgROT[0][0]) * -pitch);
+      PunROT[1][2] = -sin((1 - sgROT[0][0]) * -pitch);
+      PunROT[1][3] = SG_ZERO;
+      PunROT[2][0] = SG_ZERO;
+      PunROT[2][1] = sin((1 - sgROT[0][0]) * -pitch);
+      PunROT[2][2] = cos((1 - sgROT[0][0]) * -pitch);
+      PunROT[2][3] = SG_ZERO;
+      PunROT[3][0] = SG_ZERO;
+      PunROT[3][1] = SG_ZERO;
+      PunROT[3][2] = SG_ZERO;
+      PunROT[3][3] = SG_ONE;
+
+      sgPostMultMat4( sgTUX, PunROT );
+      sgPostMultMat4( sgTUX, VIEW_ROT );
+      sgPostMultMat4( sgTUX, sgROT );
+      sgPostMultMat4( sgTUX, sgTRANS );
+      /* end lame hack */
+
+    } else {
+      sgPostMultMat4( sgTUX, VIEW_ROT );
+      sgPostMultMat4( sgTUX, sgTRANS );
+    }
+
     sgCoord tuxpos;
     sgSetCoord( &tuxpos, sgTUX );
     _position->setTransform( &tuxpos );
+  }
+}
 
-    // START TEMPORARY KLUDGE
-    if (_prop_position != 0) {
-      double offset = -.75;
-      sgMat4 tmp;
-      sgMakeTransMat4(prop_matrix, 0, 0, offset);
-      sgMakeRotMat4(tmp, 0, 0, prop_rotation);
-      sgPostMultMat4(prop_matrix, tmp);
-      sgMakeTransMat4(tmp, 0, 0, -offset);
-      sgPostMultMat4(prop_matrix, tmp);
-      _prop_position->setTransform(prop_matrix);
-    }
-    // END_TEMPORARY KLUDGE
+FGAircraftModel::Animation
+FGAircraftModel::read_animation (const string &object_name,
+                                const SGPropertyNode * node)
+{
+  Animation animation;
+
+                               // Find the object to be animated
+  ssgEntity * target = find_named_node(_model, object_name);
+  if (target != 0) {
+    SG_LOG(SG_INPUT, SG_INFO, "  Target object is " << object_name);
+  } else {
+    animation.type = Animation::None;
+    SG_LOG(SG_INPUT, SG_ALERT, "Object " << object_name
+          << " not found in model");
+    return animation;
   }
+
+                               // Figure out the animation type
+  string type_name = node->getStringValue("type");
+  if (type_name == "spin") {
+    SG_LOG(SG_INPUT, SG_INFO, "Reading spin animation");
+    animation.type = Animation::Spin;
+  } else if (type_name == "rotate") {
+    SG_LOG(SG_INPUT, SG_INFO, "Reading rotate animation");
+    animation.type = Animation::Rotate;
+  } else if (type_name == "none") {
+    SG_LOG(SG_INPUT, SG_INFO, "Reading disabled animation");
+    animation.type = Animation::None;
+    return animation;
+  } else {
+    animation.type = Animation::None;
+    SG_LOG(SG_INPUT, SG_ALERT, "Unknown animation type " << type_name);
+    return animation;
+  }
+
+                               // Splice a transform node into the tree
+  animation.transform = new ssgTransform;
+  int nParents = target->getNumParents();
+  animation.transform->addKid(target);
+  for (int i = 0; i < nParents; i++) {
+    ssgBranch * parent = target->getParent(i);
+    parent->replaceKid(target, animation.transform);
+  }
+
+                               // Get the node
+  animation.prop =
+    fgGetNode(node->getStringValue("property", "/null"), true);
+
+  animation.position = node->getFloatValue("initial-position", 0);
+  animation.offset = node->getFloatValue("offset", 0);
+  if (node->hasValue("min")) {
+    animation.has_min = true;
+    animation.min = node->getFloatValue("min");
+  } else {
+    animation.has_min = false;
+  }
+  if (node->hasValue("max")) {
+    animation.has_max = true;
+    animation.max = node->getFloatValue("max");
+  } else {
+    animation.has_max = false;
+  }
+  animation.factor = node->getFloatValue("factor", 1);
+
+                               // Get the center and axis
+  animation.center[0] = node->getFloatValue("center/x-m", 0);
+  animation.center[1] = node->getFloatValue("center/y-m", 0);
+  animation.center[2] = node->getFloatValue("center/z-m", 0);
+  animation.axis[0] = node->getFloatValue("axis/x", 0);
+  animation.axis[1] = node->getFloatValue("axis/y", 0);
+  animation.axis[2] = node->getFloatValue("axis/z", 0);
+
+  sgNormalizeVec3(animation.axis);
+
+  return animation;
 }
 
+void
+FGAircraftModel::do_animation (Animation &animation, long elapsed_ms)
+{
+  switch (animation.type) {
+  case Animation::None:
+    return;
+  case Animation::Spin:
+  {
+    float velocity_rpms = (animation.prop->getDoubleValue()
+                          * animation.factor / 60000.0);
+    animation.position += (elapsed_ms * velocity_rpms * 360);
+    animation.setRotation();
+    return;
+  }
+  case Animation::Rotate: {
+    animation.position = ((animation.prop->getFloatValue()
+                          + animation.offset)
+                         * animation.factor);
+    if (animation.has_min && animation.position < animation.min)
+      animation.position = animation.min;
+    if (animation.has_max && animation.position > animation.max)
+      animation.position = animation.max;
+    animation.setRotation();
+    return;
+  }
+  default:
+    return;
+  }
+}
+
+/* 
+ * Transform to rotate an object around its local axis
+ * from a relative frame of reference at center -- NHV
+ */
+void
+FGAircraftModel::Animation::setRotation()
+{
+ float temp_angle = -position * 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];
+
+ sgMat4 matrix;
+ 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;
+ transform->setTransform(matrix);
+}
+
+
 // end of model.cxx