]> git.mxchange.org Git - flightgear.git/blob - src/Main/model.cxx
Patch from Jim Wilson to fix internal cockpit view rotations:
[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   : _model(0),
50     _selector(new ssgSelector),
51     _position(new ssgTransform)
52 {
53 }
54
55 FGAircraftModel::~FGAircraftModel ()
56 {
57   // since the nodes are attached to the scene graph, they'll be
58   // deleted automatically
59 }
60
61 void 
62 FGAircraftModel::init ()
63 {
64   // TODO: optionally load an XML file with a pointer to the 3D object
65   // and placement and animation info
66
67   SGPropertyNode props;
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 (unsigned int i = 0; i < animation_nodes.size(); i++) {
98     vector<SGPropertyNode *> name_nodes =
99       animation_nodes[i]->getChildren("object-name");
100     if (name_nodes.size() < 1) {
101       SG_LOG(SG_INPUT, SG_ALERT, "No object-name given for transformation");
102     } else {
103       for (unsigned int j = 0; j < name_nodes.size(); j++) {
104         _animations.push_back(read_animation(name_nodes[j]->getStringValue(),
105                                              animation_nodes[i]));
106       }
107     }
108   }
109
110                                 // Set up the alignment node
111   ssgTransform * align = new ssgTransform;
112   align->addKid(_model);
113   sgMat4 rot_matrix;
114   sgMat4 off_matrix;
115   sgMat4 res_matrix;
116   float h_rot = props.getFloatValue("/offsets/heading-deg", 0.0);
117   float p_rot = props.getFloatValue("/offsets/roll-deg", 0.0);
118   float r_rot = props.getFloatValue("/offsets/pitch-deg", 0.0);
119   float x_off = props.getFloatValue("/offsets/x-m", 0.0);
120   float y_off = props.getFloatValue("/offsets/y-m", 0.0);
121   float z_off = props.getFloatValue("/offsets/z-m", 0.0);
122   sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
123   sgMakeTransMat4(off_matrix, x_off, y_off, z_off);
124   sgMultMat4(res_matrix, off_matrix, rot_matrix);
125   align->setTransform(res_matrix);
126
127                                 // Set up the position node
128   _position->addKid(align);
129
130                                 // Set up the selector node
131   _selector->addKid(_position);
132   _selector->clrTraversalMaskBits(SSGTRAV_HOT);
133   scene->addKid(_selector);
134 }
135
136 void 
137 FGAircraftModel::bind ()
138 {
139 }
140
141 void 
142 FGAircraftModel::unbind ()
143 {
144 }
145
146 void
147 FGAircraftModel::update (int dt)
148 {
149   _current_timestamp.stamp();
150   long elapsed_ms = (_current_timestamp - _last_timestamp) / 1000;
151   _last_timestamp.stamp();
152
153   int view_number = globals->get_viewmgr()->get_current();
154
155   if (view_number == 0 && !fgGetBool("cockpit")) {
156     _selector->select(false);
157   } else {
158     for (unsigned int i = 0; i < _animations.size(); i++)
159       do_animation(_animations[i], elapsed_ms);
160
161     _selector->select(true);
162     FGViewerRPH *pilot_view =
163       (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
164     
165     sgMat4 sgTRANS;
166     sgMakeTransMat4( sgTRANS, pilot_view->get_view_pos() );
167     
168     sgVec3 ownship_up;
169     sgSetVec3( ownship_up, 0.0, 0.0, 1.0);
170     
171     sgMat4 sgROT;
172     sgMakeRotMat4( sgROT, -90.0, ownship_up );
173     
174     sgMat4 sgTUX;
175     sgCopyMat4( sgTUX, sgROT );
176     sgMat4 VIEW_ROT;
177     sgCopyMat4( VIEW_ROT, pilot_view->get_VIEW_ROT());
178     if (view_number == 0) {
179                                 // FIXME: orientation is not applied
180                                 // correctly when view is not forward
181       sgMakeRotMat4( sgROT, -pilot_view->get_view_offset()
182                      * SGD_RADIANS_TO_DEGREES, pilot_view->get_world_up() );
183
184       /* Warning lame hack from Wilson ahead */
185       /* get the pitch value */
186       sgVec3 rph;
187       sgCopyVec3(rph, pilot_view->get_rph());
188       /* double it to counter the value already in the VIEW_ROT */
189       float pitch = rph[1] * 2;
190       /* make a ROT matrix 
191          with the values waited by the X coordinate from the offset 
192          rotation see sgROT above
193       */
194       sgMat4 PunROT;
195       PunROT[0][0] = SG_ONE;
196       PunROT[0][1] = SG_ZERO;
197       PunROT[0][2] = SG_ZERO;
198       PunROT[0][3] = SG_ZERO;
199       PunROT[1][0] = SG_ZERO;
200       PunROT[1][1] = cos((1 - sgROT[0][0]) * -pitch);
201       PunROT[1][2] = -sin((1 - sgROT[0][0]) * -pitch);
202       PunROT[1][3] = SG_ZERO;
203       PunROT[2][0] = SG_ZERO;
204       PunROT[2][1] = sin((1 - sgROT[0][0]) * -pitch);
205       PunROT[2][2] = cos((1 - sgROT[0][0]) * -pitch);
206       PunROT[2][3] = SG_ZERO;
207       PunROT[3][0] = SG_ZERO;
208       PunROT[3][1] = SG_ZERO;
209       PunROT[3][2] = SG_ZERO;
210       PunROT[3][3] = SG_ONE;
211
212       sgPostMultMat4( sgTUX, PunROT );
213       sgPostMultMat4( sgTUX, VIEW_ROT );
214       sgPostMultMat4( sgTUX, sgROT );
215       sgPostMultMat4( sgTUX, sgTRANS );
216       /* end lame hack */
217
218     } else {
219       sgPostMultMat4( sgTUX, VIEW_ROT );
220       sgPostMultMat4( sgTUX, sgTRANS );
221     }
222
223     sgCoord tuxpos;
224     sgSetCoord( &tuxpos, sgTUX );
225     _position->setTransform( &tuxpos );
226   }
227 }
228
229 FGAircraftModel::Animation
230 FGAircraftModel::read_animation (const string &object_name,
231                                  const SGPropertyNode * node)
232 {
233   Animation animation;
234
235                                 // Find the object to be animated
236   ssgEntity * target = find_named_node(_model, object_name);
237   if (target != 0) {
238     SG_LOG(SG_INPUT, SG_INFO, "  Target object is " << object_name);
239   } else {
240     animation.type = Animation::None;
241     SG_LOG(SG_INPUT, SG_ALERT, "Object " << object_name
242            << " not found in model");
243     return animation;
244   }
245
246                                 // Figure out the animation type
247   string type_name = node->getStringValue("type");
248   if (type_name == "spin") {
249     SG_LOG(SG_INPUT, SG_INFO, "Reading spin animation");
250     animation.type = Animation::Spin;
251   } else if (type_name == "rotate") {
252     SG_LOG(SG_INPUT, SG_INFO, "Reading rotate animation");
253     animation.type = Animation::Rotate;
254   } else if (type_name == "none") {
255     SG_LOG(SG_INPUT, SG_INFO, "Reading disabled animation");
256     animation.type = Animation::None;
257     return animation;
258   } else {
259     animation.type = Animation::None;
260     SG_LOG(SG_INPUT, SG_ALERT, "Unknown animation type " << type_name);
261     return animation;
262   }
263
264                                 // Splice a transform node into the tree
265   animation.transform = new ssgTransform;
266   int nParents = target->getNumParents();
267   animation.transform->addKid(target);
268   for (int i = 0; i < nParents; i++) {
269     ssgBranch * parent = target->getParent(i);
270     parent->replaceKid(target, animation.transform);
271   }
272
273                                 // Get the node
274   animation.prop =
275     fgGetNode(node->getStringValue("property", "/null"), true);
276
277   animation.position = node->getFloatValue("initial-position", 0);
278   animation.offset = node->getFloatValue("offset", 0);
279   if (node->hasValue("min")) {
280     animation.has_min = true;
281     animation.min = node->getFloatValue("min");
282   } else {
283     animation.has_min = false;
284   }
285   if (node->hasValue("max")) {
286     animation.has_max = true;
287     animation.max = node->getFloatValue("max");
288   } else {
289     animation.has_max = false;
290   }
291   animation.factor = node->getFloatValue("factor", 1);
292
293                                 // Get the center and axis
294   animation.center[0] = node->getFloatValue("center/x-m", 0);
295   animation.center[1] = node->getFloatValue("center/y-m", 0);
296   animation.center[2] = node->getFloatValue("center/z-m", 0);
297   animation.axis[0] = node->getFloatValue("axis/x", 0);
298   animation.axis[1] = node->getFloatValue("axis/y", 0);
299   animation.axis[2] = node->getFloatValue("axis/z", 0);
300
301   sgNormalizeVec3(animation.axis);
302
303   return animation;
304 }
305
306 void
307 FGAircraftModel::do_animation (Animation &animation, long elapsed_ms)
308 {
309   switch (animation.type) {
310   case Animation::None:
311     return;
312   case Animation::Spin:
313   {
314     float velocity_rpms = (animation.prop->getDoubleValue()
315                            * animation.factor / 60000.0);
316     animation.position += (elapsed_ms * velocity_rpms * 360);
317     animation.setRotation();
318     return;
319   }
320   case Animation::Rotate: {
321     animation.position = ((animation.prop->getFloatValue()
322                            + animation.offset)
323                           * animation.factor);
324     if (animation.has_min && animation.position < animation.min)
325       animation.position = animation.min;
326     if (animation.has_max && animation.position > animation.max)
327       animation.position = animation.max;
328     animation.setRotation();
329     return;
330   }
331   default:
332     return;
333   }
334 }
335
336 /* 
337  * Transform to rotate an object around its local axis
338  * from a relative frame of reference at center -- NHV
339  */
340 void
341 FGAircraftModel::Animation::setRotation()
342 {
343  float temp_angle = -position * SG_DEGREES_TO_RADIANS ;
344  
345  float s = (float) sin ( temp_angle ) ;
346  float c = (float) cos ( temp_angle ) ;
347  float t = SG_ONE - c ;
348
349  // axis was normalized at load time 
350  // hint to the compiler to put these into FP registers
351  float x = axis[0];
352  float y = axis[1];
353  float z = axis[2];
354
355  sgMat4 matrix;
356  matrix[0][0] = t * x * x + c ;
357  matrix[0][1] = t * y * x - s * z ;
358  matrix[0][2] = t * z * x + s * y ;
359  matrix[0][3] = SG_ZERO;
360  
361  matrix[1][0] = t * x * y + s * z ;
362  matrix[1][1] = t * y * y + c ;
363  matrix[1][2] = t * z * y - s * x ;
364  matrix[1][3] = SG_ZERO;
365  
366  matrix[2][0] = t * x * z - s * y ;
367  matrix[2][1] = t * y * z + s * x ;
368  matrix[2][2] = t * z * z + c ;
369  matrix[2][3] = SG_ZERO;
370
371   // hint to the compiler to put these into FP registers
372  x = center[0];
373  y = center[1];
374  z = center[2];
375  
376  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
377  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
378  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
379  matrix[3][3] = SG_ONE;
380  
381  transform->setTransform(matrix);
382 }
383
384
385 // end of model.cxx