X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fmodel.cxx;h=8016f97ca3b6e5da9ac240e6d5158405ad210257;hb=a2acc953ae337d45954382904e0d1ea6c63b48a0;hp=5d20a357bf11098cd117671ac3ac4729ea35c206;hpb=3d4bec275b3c10ff7c07483b536a1903701a45c0;p=flightgear.git diff --git a/src/Main/model.cxx b/src/Main/model.cxx index 5d20a357b..8016f97ca 100644 --- a/src/Main/model.cxx +++ b/src/Main/model.cxx @@ -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 animation_nodes = + props.getChildren("animation"); + for (unsigned int i = 0; i < animation_nodes.size(); i++) { + vector 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