1 // model.cxx - manage a 3D aircraft model.
2 // Written by David Megginson, started 2002.
4 // This file is in the Public Domain, and comes with no warranty.
13 #include <simgear/compiler.h>
14 #include <simgear/debug/logstream.hxx>
15 #include <simgear/misc/exception.hxx>
16 #include <simgear/misc/sg_path.hxx>
18 #include "globals.hxx"
19 #include "fg_props.hxx"
20 #include "viewmgr.hxx"
23 extern unsigned long int fgSimTime; // FIXME: this is ugly
25 extern ssgRoot * scene; // FIXME: from main.cxx
27 FGAircraftModel current_model; // FIXME: add to globals
31 find_named_node (ssgEntity * node, const string &name)
33 char * node_name = node->getName();
34 if (node_name != 0 && name == node_name)
36 else if (node->isAKindOf(ssgTypeBranch())) {
37 int nKids = node->getNumKids();
38 for (int i = 0; i < nKids; i++) {
40 find_named_node(((ssgBranch*)node)->getKid(i), name);
48 FGAircraftModel::FGAircraftModel ()
49 : _props(new SGPropertyNode),
51 _selector(new ssgSelector),
52 _position(new ssgTransform)
56 FGAircraftModel::~FGAircraftModel ()
59 // since the nodes are attached to the scene graph, they'll be
60 // deleted automatically
64 FGAircraftModel::init ()
66 // TODO: optionally load an XML file with a pointer to the 3D object
67 // and placement and animation info
69 SG_LOG(SG_INPUT, SG_INFO, "Initializing aircraft 3D model");
71 // Load the 3D aircraft object itself
72 SGPath path = globals->get_fg_root();
73 path.append(fgGetString("/sim/model/path", "Models/Geometry/glider.ac"));
75 if (path.str().substr(path.str().size() - 4, 4) == ".xml") {
76 readProperties(path.str(), _props);
77 if (_props->hasValue("/path")) {
79 path.append(_props->getStringValue("/path"));
81 path = globals->get_fg_root();
82 path.append("Models/Geometry/glider.ac");
86 ssgTexturePath((char *)path.dir().c_str());
87 _model = ssgLoad((char *)path.c_str());
89 _model = ssgLoad((char *)"Models/Geometry/glider.ac");
91 throw sg_exception("Failed to load an aircraft model");
95 vector<SGPropertyNode *> animation_nodes =
96 _props->getChildren("animation");
97 for (int i = 0; i < animation_nodes.size(); i++) {
98 _animations.push_back(read_animation(animation_nodes[i]));
101 // Set up the alignment node
102 ssgTransform * align = new ssgTransform;
103 align->addKid(_model);
107 float h_rot = _props->getFloatValue("/offsets/heading-deg", 0.0);
108 float p_rot = _props->getFloatValue("/offsets/roll-deg", 0.0);
109 float r_rot = _props->getFloatValue("/offsets/pitch-deg", 0.0);
110 float x_off = _props->getFloatValue("/offsets/x-m", 0.0);
111 float y_off = _props->getFloatValue("/offsets/y-m", 0.0);
112 float z_off = _props->getFloatValue("/offsets/z-m", 0.0);
113 sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
114 sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
115 sgMultMat4(res_matrix, off_matrix, rot_matrix);
116 align->setTransform(res_matrix);
118 // Set up the position node
119 _position->addKid(align);
121 // Set up the selector node
122 _selector->addKid(_position);
123 _selector->clrTraversalMaskBits(SSGTRAV_HOT);
124 scene->addKid(_selector);
128 FGAircraftModel::bind ()
133 FGAircraftModel::unbind ()
138 FGAircraftModel::update (int dt)
140 _current_timestamp.stamp();
141 long elapsed_ms = (_current_timestamp - _last_timestamp) / 1000;
142 _last_timestamp.stamp();
144 if (globals->get_viewmgr()->get_current() == 0) {
145 _selector->select(false);
147 for (int i = 0; i < _animations.size(); i++)
148 do_animation(_animations[i], elapsed_ms);
150 _selector->select(true);
151 FGViewerRPH *pilot_view =
152 (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
155 sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
158 sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
161 sgMakeRotMat4( sgROT, -90.0, ownship_up );
164 sgCopyMat4( sgTUX, sgROT );
165 sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
166 sgPostMultMat4( sgTUX, sgTRANS );
169 sgSetCoord( &tuxpos, sgTUX );
170 _position->setTransform( &tuxpos );
175 FGAircraftModel::Animation
176 FGAircraftModel::read_animation (const SGPropertyNode * node)
180 // Figure out the animation type
181 string type_name = node->getStringValue("type");
182 if (type_name == "spin") {
183 SG_LOG(SG_INPUT, SG_INFO, "Reading spin animation");
184 animation.type = Animation::Spin;
185 } else if (type_name == "rotate") {
186 SG_LOG(SG_INPUT, SG_INFO, "Reading rotate animation");
187 animation.type = Animation::Rotate;
188 } else if (type_name == "none") {
189 SG_LOG(SG_INPUT, SG_INFO, "Reading disabled animation");
190 animation.type = Animation::None;
193 animation.type = Animation::None;
194 SG_LOG(SG_INPUT, SG_ALERT, "Unknown animation type " << type_name);
198 // Find the object to be animated
199 string object_name = node->getStringValue("object-name");
200 ssgEntity * target = find_named_node(_model, object_name);
202 SG_LOG(SG_INPUT, SG_INFO, " Target object is " << object_name);
204 animation.type = Animation::None;
205 SG_LOG(SG_INPUT, SG_ALERT, "Object " << object_name
206 << " not found in model");
210 // Splice a transform node into the tree
211 animation.transform = new ssgTransform;
212 int nParents = target->getNumParents();
213 animation.transform->addKid(target);
214 for (int i = 0; i < nParents; i++) {
215 ssgBranch * parent = target->getParent(i);
216 parent->replaceKid(target, animation.transform);
221 fgGetNode(node->getStringValue("property", "/null"), true);
223 animation.position = node->getFloatValue("initial-position", 0);
224 animation.factor = node->getFloatValue("factor", 1);
226 // Get the center and axis
227 animation.center_x = node->getFloatValue("center/x-m", 0);
228 animation.center_y = node->getFloatValue("center/y-m", 0);
229 animation.center_z = node->getFloatValue("center/z-m", 0);
230 animation.axis_x = node->getFloatValue("axis/x", 0);
231 animation.axis_y = node->getFloatValue("axis/y", 1);
232 animation.axis_z = node->getFloatValue("axis/z", 0);
238 FGAircraftModel::do_animation (Animation &animation, long elapsed_ms)
240 switch (animation.type) {
241 case Animation::None:
243 case Animation::Spin: {
244 float velocity_rpms = animation.prop->getDoubleValue()
245 * animation.factor / 60000.0;
246 animation.position += (elapsed_ms * velocity_rpms * 360);
247 while (animation.position >= 360)
248 animation.position -= 360;
249 sgMakeTransMat4(animation.matrix, -animation.center_x,
250 -animation.center_y, -animation.center_z);
252 sgSetVec3(axis, animation.axis_x, animation.axis_y, animation.axis_z);
254 sgMakeRotMat4(tmp, animation.position, axis);
255 sgPostMultMat4(animation.matrix, tmp);
256 sgMakeTransMat4(tmp, animation.center_x,
257 animation.center_y, animation.center_z);
258 sgPostMultMat4(animation.matrix, tmp);
259 animation.transform->setTransform(animation.matrix);
262 case Animation::Rotate: {
263 animation.position = animation.prop->getFloatValue() * animation.factor;
264 sgMakeTransMat4(animation.matrix, -animation.center_x,
265 -animation.center_y, -animation.center_z);
267 sgSetVec3(axis, animation.axis_x, animation.axis_y, animation.axis_z);
269 sgMakeRotMat4(tmp, animation.position, axis);
270 sgPostMultMat4(animation.matrix, tmp);
271 sgMakeTransMat4(tmp, animation.center_x,
272 animation.center_y, animation.center_z);
273 sgPostMultMat4(animation.matrix, tmp);
274 animation.transform->setTransform(animation.matrix);