]> git.mxchange.org Git - flightgear.git/blob - src/Main/model.cxx
Added rotation animations, and a factor parameter for scaling.
[flightgear.git] / src / Main / model.cxx
1 // model.cxx - manage a 3D aircraft model.
2 // Written by David Megginson, started 2002.
3 //
4 // This file is in the Public Domain, and comes with no warranty.
5
6 #ifdef HAVE_CONFIG_H
7 #  include <config.h>
8 #endif
9
10 #include <plib/sg.h>
11 #include <plib/ssg.h>
12
13 #include <simgear/compiler.h>
14 #include <simgear/debug/logstream.hxx>
15 #include <simgear/misc/exception.hxx>
16 #include <simgear/misc/sg_path.hxx>
17
18 #include "globals.hxx"
19 #include "fg_props.hxx"
20 #include "viewmgr.hxx"
21 #include "model.hxx"
22
23 extern unsigned long int fgSimTime; // FIXME: this is ugly
24
25 extern ssgRoot * scene;         // FIXME: from main.cxx
26
27 FGAircraftModel current_model;  // FIXME: add to globals
28
29
30 static ssgEntity *
31 find_named_node (ssgEntity * node, const string &name)
32 {
33   char * node_name = node->getName();
34   if (node_name != 0 && name == node_name)
35     return node;
36   else if (node->isAKindOf(ssgTypeBranch())) {
37     int nKids = node->getNumKids();
38     for (int i = 0; i < nKids; i++) {
39       ssgEntity * result =
40         find_named_node(((ssgBranch*)node)->getKid(i), name);
41       if (result != 0)
42         return result;
43     }
44   } 
45   return 0;
46 }
47
48 FGAircraftModel::FGAircraftModel ()
49   : _props(new SGPropertyNode),
50     _model(0),
51     _selector(new ssgSelector),
52     _position(new ssgTransform)
53 {
54 }
55
56 FGAircraftModel::~FGAircraftModel ()
57 {
58   delete _props;
59   // since the nodes are attached to the scene graph, they'll be
60   // deleted automatically
61 }
62
63 void 
64 FGAircraftModel::init ()
65 {
66   // TODO: optionally load an XML file with a pointer to the 3D object
67   // and placement and animation info
68
69   SG_LOG(SG_INPUT, SG_INFO, "Initializing aircraft 3D model");
70
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"));
74
75   if (path.str().substr(path.str().size() - 4, 4) == ".xml") {
76     readProperties(path.str(), _props);
77     if (_props->hasValue("/path")) {
78       path = path.dir();;
79       path.append(_props->getStringValue("/path"));
80     } else {
81       path = globals->get_fg_root();
82       path.append("Models/Geometry/glider.ac");
83     }
84   }
85
86   ssgTexturePath((char *)path.dir().c_str());
87   _model = ssgLoad((char *)path.c_str());
88   if (_model == 0) {
89     _model = ssgLoad((char *)"Models/Geometry/glider.ac");
90     if (_model == 0)
91       throw sg_exception("Failed to load an aircraft model");
92   }
93
94                                 // Load animations
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]));
99   }
100
101                                 // Set up the alignment node
102   ssgTransform * align = new ssgTransform;
103   align->addKid(_model);
104   sgMat4 rot_matrix;
105   sgMat4 off_matrix;
106   sgMat4 res_matrix;
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);
117
118                                 // Set up the position node
119   _position->addKid(align);
120
121                                 // Set up the selector node
122   _selector->addKid(_position);
123   _selector->clrTraversalMaskBits(SSGTRAV_HOT);
124   scene->addKid(_selector);
125 }
126
127 void 
128 FGAircraftModel::bind ()
129 {
130 }
131
132 void 
133 FGAircraftModel::unbind ()
134 {
135 }
136
137 void
138 FGAircraftModel::update (int dt)
139 {
140   _current_timestamp.stamp();
141   long elapsed_ms = (_current_timestamp - _last_timestamp) / 1000;
142   _last_timestamp.stamp();
143
144   if (globals->get_viewmgr()->get_current() == 0) {
145     _selector->select(false);
146   } else {
147     for (int i = 0; i < _animations.size(); i++)
148       do_animation(_animations[i], elapsed_ms);
149
150     _selector->select(true);
151     FGViewerRPH *pilot_view =
152       (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
153     
154     sgMat4 sgTRANS;
155     sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
156     
157     sgVec3 ownship_up;
158     sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
159     
160     sgMat4 sgROT;
161     sgMakeRotMat4( sgROT, -90.0, ownship_up );
162     
163     sgMat4 sgTUX;
164     sgCopyMat4( sgTUX, sgROT );
165     sgPostMultMat4( sgTUX, pilot_view->get_VIEW_ROT() );
166     sgPostMultMat4( sgTUX, sgTRANS );
167     
168     sgCoord tuxpos;
169     sgSetCoord( &tuxpos, sgTUX );
170     _position->setTransform( &tuxpos );
171   }
172
173 }
174
175 FGAircraftModel::Animation
176 FGAircraftModel::read_animation (const SGPropertyNode * node)
177 {
178   Animation animation;
179
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;
191     return animation;
192   } else {
193     animation.type = Animation::None;
194     SG_LOG(SG_INPUT, SG_ALERT, "Unknown animation type " << type_name);
195     return animation;
196   }
197
198                                 // Find the object to be animated
199   string object_name = node->getStringValue("object-name");
200   ssgEntity * target = find_named_node(_model, object_name);
201   if (target != 0) {
202     SG_LOG(SG_INPUT, SG_INFO, "  Target object is " << object_name);
203   } else {
204     animation.type = Animation::None;
205     SG_LOG(SG_INPUT, SG_ALERT, "Object " << object_name
206            << " not found in model");
207     return animation;
208   }
209
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);
217   }
218
219                                 // Get the node
220   animation.prop =
221     fgGetNode(node->getStringValue("property", "/null"), true);
222
223   animation.position = node->getFloatValue("initial-position", 0);
224   animation.factor = node->getFloatValue("factor", 1);
225
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);
233
234   return animation;
235 }
236
237 void
238 FGAircraftModel::do_animation (Animation &animation, long elapsed_ms)
239 {
240   switch (animation.type) {
241   case Animation::None:
242     return;
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);
251     sgVec3 axis;
252     sgSetVec3(axis, animation.axis_x, animation.axis_y, animation.axis_z);
253     sgMat4 tmp;
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);
260     return;
261   }
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);
266     sgVec3 axis;
267     sgSetVec3(axis, animation.axis_x, animation.axis_y, animation.axis_z);
268     sgMat4 tmp;
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);
275     return;
276   }
277   default:
278     return;
279   }
280 }
281
282 // end of model.cxx