}
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
}
// 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");
}
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);
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 );
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