]> git.mxchange.org Git - flightgear.git/blob - src/Model/model.cxx
Removed debug print statements.
[flightgear.git] / src / Model / 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 <string.h>             // for strcmp()
11
12 #include <plib/sg.h>
13 #include <plib/ssg.h>
14
15 #include <simgear/compiler.h>
16 #include <simgear/debug/logstream.hxx>
17 #include <simgear/math/interpolater.hxx>
18 #include <simgear/math/point3d.hxx>
19 #include <simgear/math/sg_geodesy.hxx>
20 #include <simgear/misc/exception.hxx>
21 #include <simgear/misc/sg_path.hxx>
22
23 #include <Main/fg_props.hxx>
24 #include <Main/globals.hxx>
25 #include <Main/location.hxx>
26 #include <Scenery/scenery.hxx>
27
28 #include "model.hxx"
29 #include "panelnode.hxx"
30
31
32 \f
33 ////////////////////////////////////////////////////////////////////////
34 // Static utility functions.
35 ////////////////////////////////////////////////////////////////////////
36
37 /**
38  * Callback to update an animation.
39  */
40 static int
41 animation_callback (ssgEntity * entity, int mask)
42 {
43     ((Animation *)entity->getUserData())->update();
44     return true;
45 }
46
47
48 /**
49  * Locate a named SSG node in a branch.
50  */
51 static ssgEntity *
52 find_named_node (ssgEntity * node, const char * name)
53 {
54   char * node_name = node->getName();
55   if (node_name != 0 && !strcmp(name, node_name))
56     return node;
57   else if (node->isAKindOf(ssgTypeBranch())) {
58     int nKids = node->getNumKids();
59     for (int i = 0; i < nKids; i++) {
60       ssgEntity * result =
61         find_named_node(((ssgBranch*)node)->getKid(i), name);
62       if (result != 0)
63         return result;
64     }
65   } 
66   return 0;
67 }
68
69 /**
70  * Splice a branch in between all child nodes and their parents.
71  */
72 static void
73 splice_branch (ssgBranch * branch, ssgEntity * child)
74 {
75   int nParents = child->getNumParents();
76   branch->addKid(child);
77   for (int i = 0; i < nParents; i++) {
78     ssgBranch * parent = child->getParent(i);
79     parent->replaceKid(child, branch);
80   }
81 }
82
83 /**
84  * Set up the transform matrix for a spin or rotation.
85  */
86 static void
87 set_rotation (sgMat4 &matrix, double position_deg,
88               sgVec3 &center, sgVec3 &axis)
89 {
90  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
91  
92  float s = (float) sin ( temp_angle ) ;
93  float c = (float) cos ( temp_angle ) ;
94  float t = SG_ONE - c ;
95
96  // axis was normalized at load time 
97  // hint to the compiler to put these into FP registers
98  float x = axis[0];
99  float y = axis[1];
100  float z = axis[2];
101
102  matrix[0][0] = t * x * x + c ;
103  matrix[0][1] = t * y * x - s * z ;
104  matrix[0][2] = t * z * x + s * y ;
105  matrix[0][3] = SG_ZERO;
106  
107  matrix[1][0] = t * x * y + s * z ;
108  matrix[1][1] = t * y * y + c ;
109  matrix[1][2] = t * z * y - s * x ;
110  matrix[1][3] = SG_ZERO;
111  
112  matrix[2][0] = t * x * z - s * y ;
113  matrix[2][1] = t * y * z + s * x ;
114  matrix[2][2] = t * z * z + c ;
115  matrix[2][3] = SG_ZERO;
116
117   // hint to the compiler to put these into FP registers
118  x = center[0];
119  y = center[1];
120  z = center[2];
121  
122  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
123  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
124  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
125  matrix[3][3] = SG_ONE;
126 }
127
128 /**
129  * Set up the transform matrix for a translation.
130  */
131 static void
132 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
133 {
134   sgVec3 xyz;
135   sgScaleVec3(xyz, axis, position_m);
136   sgMakeTransMat4(matrix, xyz);
137 }
138
139
140 /**
141  * Make an offset matrix from rotations and position offset.
142  */
143 static void
144 make_offsets_matrix (sgMat4 * result, double h_rot, double p_rot, double r_rot,
145                      double x_off, double y_off, double z_off)
146 {
147   sgMat4 rot_matrix;
148   sgMat4 pos_matrix;
149   sgMakeRotMat4(rot_matrix, h_rot, p_rot, r_rot);
150   sgMakeTransMat4(pos_matrix, x_off, y_off, z_off);
151   sgMultMat4(*result, pos_matrix, rot_matrix);
152 }
153
154
155 /**
156  * Read an interpolation table from properties.
157  */
158 static SGInterpTable *
159 read_interpolation_table (SGPropertyNode_ptr props)
160 {
161   SGPropertyNode_ptr table_node = props->getNode("interpolation");
162   if (table_node != 0) {
163     SGInterpTable * table = new SGInterpTable();
164     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
165     for (unsigned int i = 0; i < entries.size(); i++)
166       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
167                       entries[i]->getDoubleValue("dep", 0.0));
168     return table;
169   } else {
170     return 0;
171   }
172 }
173
174
175 static void
176 make_animation (ssgBranch * model,
177                 const char * name,
178                 vector<SGPropertyNode_ptr> &name_nodes,
179                 SGPropertyNode_ptr node)
180 {
181   Animation * animation = 0;
182   const char * type = node->getStringValue("type");
183   if (!strcmp("none", type)) {
184     animation = new NullAnimation(node);
185   } else if (!strcmp("range", type)) {
186     animation = new RangeAnimation(node);
187   } else if (!strcmp("billboard", type)) {
188     animation = new BillboardAnimation(node);
189   } else if (!strcmp("select", type)) {
190     animation = new SelectAnimation(node);
191   } else if (!strcmp("spin", type)) {
192     animation = new SpinAnimation(node);
193   } else if (!strcmp("rotate", type)) {
194     animation = new RotateAnimation(node);
195   } else if (!strcmp("translate", type)) {
196     animation = new TranslateAnimation(node);
197   } else {
198     animation = new NullAnimation(node);
199     SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
200   }
201
202   if (name != 0)
203       animation->setName((char *)name);
204
205   ssgEntity * object;
206   if (name_nodes.size() > 0) {
207     object = find_named_node(model, name_nodes[0]->getStringValue());
208     if (object == 0) {
209       SG_LOG(SG_INPUT, SG_WARN, "Object " << name_nodes[0]->getStringValue()
210              << " not found");
211       delete animation;
212       animation = 0;
213     }
214   } else {
215     object = model;
216   }
217   
218   ssgBranch * branch = animation->getBranch();
219   splice_branch(branch, object);
220
221   for (int i = 1; i < name_nodes.size(); i++) {
222       const char * name = name_nodes[i]->getStringValue();
223       object = find_named_node(model, name);
224       if (object == 0) {
225           SG_LOG(SG_INPUT, SG_WARN, "Object " << name << " not found");
226           delete animation;
227           animation = 0;
228       }
229       ssgBranch * oldParent = object->getParent(0);
230       branch->addKid(object);
231       oldParent->removeKid(object);
232   }
233
234   branch->setUserData(animation);
235   branch->setTravCallback(SSG_CALLBACK_PRETRAV, animation_callback);
236 }
237
238
239 \f
240 ////////////////////////////////////////////////////////////////////////
241 // Global functions.
242 ////////////////////////////////////////////////////////////////////////
243
244 ssgBranch *
245 fgLoad3DModel (const string &path)
246 {
247   ssgBranch * model = 0;
248   SGPropertyNode props;
249
250                                 // Load the 3D aircraft object itself
251   SGPath xmlpath;
252   SGPath modelpath = path;
253   if ( path[ 0 ] == '/' || path[ 0 ] == '\\' || ( isalpha( path[ 0 ] ) && path[ 1 ] == ':' ) ) {
254     xmlpath = modelpath;
255   }
256   else {
257     xmlpath = globals->get_fg_root();
258     xmlpath.append(modelpath.str());
259   }
260
261                                 // Check for an XML wrapper
262   if (xmlpath.str().substr(xmlpath.str().size() - 4, 4) == ".xml") {
263     readProperties(xmlpath.str(), &props);
264     if (props.hasValue("/path")) {
265       modelpath = modelpath.dir();
266       modelpath.append(props.getStringValue("/path"));
267     } else {
268       if (model == 0)
269         model = new ssgBranch;
270     }
271   }
272
273                                 // Assume that textures are in
274                                 // the same location as the XML file.
275   if (model == 0) {
276     ssgTexturePath((char *)xmlpath.dir().c_str());
277     model = (ssgBranch *)ssgLoad((char *)modelpath.c_str());
278     if (model == 0)
279       throw sg_exception("Failed to load 3D model");
280   }
281
282                                 // Set up the alignment node
283   ssgTransform * align = new ssgTransform;
284   align->addKid(model);
285   sgMat4 res_matrix;
286   make_offsets_matrix(&res_matrix,
287                       props.getFloatValue("/offsets/heading-deg", 0.0),
288                       props.getFloatValue("/offsets/roll-deg", 0.0),
289                       props.getFloatValue("/offsets/pitch-deg", 0.0),
290                       props.getFloatValue("/offsets/x-m", 0.0),
291                       props.getFloatValue("/offsets/y-m", 0.0),
292                       props.getFloatValue("/offsets/z-m", 0.0));
293   align->setTransform(res_matrix);
294
295                                 // Load animations
296   vector<SGPropertyNode_ptr> animation_nodes = props.getChildren("animation");
297   unsigned int i;
298   for (i = 0; i < animation_nodes.size(); i++) {
299     const char * name = animation_nodes[i]->getStringValue("name", 0);
300     vector<SGPropertyNode_ptr> name_nodes =
301       animation_nodes[i]->getChildren("object-name");
302     make_animation(model, name, name_nodes, animation_nodes[i]);
303   }
304
305                                 // Load panels
306   vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
307   for (i = 0; i < panel_nodes.size(); i++) {
308     printf("Reading a panel in model.cxx\n");
309     FGPanelNode * panel = new FGPanelNode(panel_nodes[i]);
310     model->addKid(panel);
311   }
312
313                                 // Load sub-models
314   vector<SGPropertyNode_ptr> model_nodes = props.getChildren("model");
315   for (i = 0; i < model_nodes.size(); i++) {
316     SGPropertyNode_ptr node = model_nodes[i];
317     ssgTransform * align = new ssgTransform;
318     sgMat4 res_matrix;
319     make_offsets_matrix(&res_matrix,
320                         node->getFloatValue("offsets/heading-deg", 0.0),
321                         node->getFloatValue("offsets/roll-deg", 0.0),
322                         node->getFloatValue("offsets/pitch-deg", 0.0),
323                         node->getFloatValue("offsets/x-m", 0.0),
324                         node->getFloatValue("offsets/y-m", 0.0),
325                         node->getFloatValue("offsets/z-m", 0.0));
326     align->setTransform(res_matrix);
327
328     ssgBranch * kid = fgLoad3DModel(node->getStringValue("path"));
329     align->addKid(kid);
330     model->addKid(align);
331   }
332
333   return model;
334 }
335
336
337 \f
338 ////////////////////////////////////////////////////////////////////////
339 // Implementation of Animation
340 ////////////////////////////////////////////////////////////////////////
341
342 Animation::Animation (SGPropertyNode_ptr props, ssgBranch * branch)
343     : _branch(branch)
344 {
345     _branch->setName(props->getStringValue("name", 0));
346 }
347
348 Animation::~Animation ()
349 {
350 }
351
352
353 \f
354 ////////////////////////////////////////////////////////////////////////
355 // Implementation of NullAnimation
356 ////////////////////////////////////////////////////////////////////////
357
358 NullAnimation::NullAnimation (SGPropertyNode_ptr props)
359   : Animation(props, new ssgBranch)
360 {
361 }
362
363 NullAnimation::~NullAnimation ()
364 {
365 }
366
367 void
368 NullAnimation::update ()
369 {
370 }
371
372
373 \f
374 ////////////////////////////////////////////////////////////////////////
375 // Implementation of RangeAnimation
376 ////////////////////////////////////////////////////////////////////////
377
378 RangeAnimation::RangeAnimation (SGPropertyNode_ptr props)
379   : Animation(props, new ssgRangeSelector)
380 {
381     float ranges[] = { props->getFloatValue("min-m", 0),
382                        props->getFloatValue("max-m", 5000) };
383     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
384                        
385 }
386
387 RangeAnimation::~RangeAnimation ()
388 {
389 }
390
391 void
392 RangeAnimation::update ()
393 {
394 }
395
396
397 \f
398 ////////////////////////////////////////////////////////////////////////
399 // Implementation of BillboardAnimation
400 ////////////////////////////////////////////////////////////////////////
401
402 BillboardAnimation::BillboardAnimation (SGPropertyNode_ptr props)
403     : Animation(props, new ssgCutout(props->getBoolValue("spherical", true)))
404 {
405 }
406
407 BillboardAnimation::~BillboardAnimation ()
408 {
409 }
410
411 void
412 BillboardAnimation::update ()
413 {
414 }
415
416
417 \f
418 ////////////////////////////////////////////////////////////////////////
419 // Implementation of SelectAnimation
420 ////////////////////////////////////////////////////////////////////////
421
422 SelectAnimation::SelectAnimation (SGPropertyNode_ptr props)
423   : Animation(props, new ssgSelector),
424     _condition(0)
425 {
426   SGPropertyNode_ptr node = props->getChild("condition");
427   if (node != 0)
428     _condition = fgReadCondition(node);
429 }
430
431 SelectAnimation::~SelectAnimation ()
432 {
433   delete _condition;
434 }
435
436 void
437 SelectAnimation::update ()
438 {
439   if (_condition != 0 && _condition->test()) 
440       ((ssgSelector *)_branch)->select(0xffff);
441   else
442       ((ssgSelector *)_branch)->select(0x0000);
443 }
444
445
446 \f
447 ////////////////////////////////////////////////////////////////////////
448 // Implementation of SpinAnimation
449 ////////////////////////////////////////////////////////////////////////
450
451 SpinAnimation::SpinAnimation (SGPropertyNode_ptr props)
452   : Animation(props, new ssgTransform),
453     _prop(fgGetNode(props->getStringValue("property", "/null"), true)),
454     _factor(props->getDoubleValue("factor", 1.0)),
455     _position_deg(props->getDoubleValue("starting-position-deg", 0)),
456     _last_time_sec(globals->get_sim_time_sec())
457 {
458     _center[0] = props->getFloatValue("center/x-m", 0);
459     _center[1] = props->getFloatValue("center/y-m", 0);
460     _center[2] = props->getFloatValue("center/z-m", 0);
461     _axis[0] = props->getFloatValue("axis/x", 0);
462     _axis[1] = props->getFloatValue("axis/y", 0);
463     _axis[2] = props->getFloatValue("axis/z", 0);
464     sgNormalizeVec3(_axis);
465 }
466
467 SpinAnimation::~SpinAnimation ()
468 {
469 }
470
471 void
472 SpinAnimation::update ()
473 {
474   double sim_time = globals->get_sim_time_sec();
475   double dt = sim_time - _last_time_sec;
476   _last_time_sec = sim_time;
477
478   float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
479   _position_deg += (dt * velocity_rpms * 360);
480   while (_position_deg < 0)
481     _position_deg += 360.0;
482   while (_position_deg >= 360.0)
483     _position_deg -= 360.0;
484   set_rotation(_matrix, _position_deg, _center, _axis);
485   ((ssgTransform *)_branch)->setTransform(_matrix);
486 }
487
488
489 \f
490 ////////////////////////////////////////////////////////////////////////
491 // Implementation of RotateAnimation
492 ////////////////////////////////////////////////////////////////////////
493
494 RotateAnimation::RotateAnimation (SGPropertyNode_ptr props)
495     : Animation(props, new ssgTransform),
496       _prop(fgGetNode(props->getStringValue("property", "/null"), true)),
497       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
498       _factor(props->getDoubleValue("factor", 1.0)),
499       _table(read_interpolation_table(props)),
500       _has_min(props->hasValue("min-deg")),
501       _min_deg(props->getDoubleValue("min-deg")),
502       _has_max(props->hasValue("max-deg")),
503       _max_deg(props->getDoubleValue("max-deg")),
504       _position_deg(props->getDoubleValue("starting-position-deg", 0))
505 {
506   _center[0] = props->getFloatValue("center/x-m", 0);
507   _center[1] = props->getFloatValue("center/y-m", 0);
508   _center[2] = props->getFloatValue("center/z-m", 0);
509   _axis[0] = props->getFloatValue("axis/x", 0);
510   _axis[1] = props->getFloatValue("axis/y", 0);
511   _axis[2] = props->getFloatValue("axis/z", 0);
512   sgNormalizeVec3(_axis);
513 }
514
515 RotateAnimation::~RotateAnimation ()
516 {
517   delete _table;
518 }
519
520 void
521 RotateAnimation::update ()
522 {
523   if (_table == 0) {
524     _position_deg = (_prop->getDoubleValue() + _offset_deg) * _factor;
525    if (_has_min && _position_deg < _min_deg)
526      _position_deg = _min_deg;
527    if (_has_max && _position_deg > _max_deg)
528      _position_deg = _max_deg;
529   } else {
530     _position_deg = _table->interpolate(_prop->getDoubleValue());
531   }
532   set_rotation(_matrix, _position_deg, _center, _axis);
533   ((ssgTransform *)_branch)->setTransform(_matrix);
534 }
535
536
537 \f
538 ////////////////////////////////////////////////////////////////////////
539 // Implementation of TranslateAnimation
540 ////////////////////////////////////////////////////////////////////////
541
542 TranslateAnimation::TranslateAnimation (SGPropertyNode_ptr props)
543   : Animation(props, new ssgTransform),
544     _prop(fgGetNode(props->getStringValue("property", "/null"), true)),
545     _offset_m(props->getDoubleValue("offset-m", 0.0)),
546     _factor(props->getDoubleValue("factor", 1.0)),
547     _table(read_interpolation_table(props)),
548     _has_min(props->hasValue("min-m")),
549     _min_m(props->getDoubleValue("min-m")),
550     _has_max(props->hasValue("max-m")),
551     _max_m(props->getDoubleValue("max-m")),
552     _position_m(props->getDoubleValue("starting-position-m", 0))
553 {
554   _axis[0] = props->getFloatValue("axis/x", 0);
555   _axis[1] = props->getFloatValue("axis/y", 0);
556   _axis[2] = props->getFloatValue("axis/z", 0);
557   sgNormalizeVec3(_axis);
558 }
559
560 TranslateAnimation::~TranslateAnimation ()
561 {
562   delete _table;
563 }
564
565 void
566 TranslateAnimation::update ()
567 {
568   if (_table == 0) {
569     _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
570     if (_has_min && _position_m < _min_m)
571       _position_m = _min_m;
572     if (_has_max && _position_m > _max_m)
573       _position_m = _max_m;
574   } else {
575     _position_m = _table->interpolate(_prop->getDoubleValue());
576   }
577   set_translation(_matrix, _position_m, _axis);
578   ((ssgTransform *)_branch)->setTransform(_matrix);
579 }
580
581
582 \f
583 ////////////////////////////////////////////////////////////////////////
584 // Implementation of FGModelPlacement.
585 ////////////////////////////////////////////////////////////////////////
586
587 FGModelPlacement::FGModelPlacement ()
588   : _lon_deg(0),
589     _lat_deg(0),
590     _elev_ft(0),
591     _roll_deg(0),
592     _pitch_deg(0),
593     _heading_deg(0),
594     _selector(new ssgSelector),
595     _position(new ssgTransform),
596     _location(new FGLocation)
597 {
598 }
599
600 FGModelPlacement::~FGModelPlacement ()
601 {
602 }
603
604 void
605 FGModelPlacement::init (const string &path)
606 {
607   ssgBranch * model = fgLoad3DModel(path);
608   if (model != 0)
609       _position->addKid(model);
610   _selector->addKid(_position);
611   _selector->clrTraversalMaskBits(SSGTRAV_HOT);
612 }
613
614 void
615 FGModelPlacement::update ()
616 {
617   _location->setPosition( _lon_deg, _lat_deg, _elev_ft );
618   _location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
619
620   sgMat4 POS;
621   sgCopyMat4(POS, _location->getTransformMatrix());
622   
623   sgVec3 trans;
624   sgCopyVec3(trans, _location->get_view_pos());
625
626   for(int i = 0; i < 4; i++) {
627     float tmp = POS[i][3];
628     for( int j=0; j<3; j++ ) {
629       POS[i][j] += (tmp * trans[j]);
630     }
631   }
632   _position->setTransform(POS);
633 }
634
635 bool
636 FGModelPlacement::getVisible () const
637 {
638   return (_selector->getSelect() != 0);
639 }
640
641 void
642 FGModelPlacement::setVisible (bool visible)
643 {
644   _selector->select(visible);
645 }
646
647 void
648 FGModelPlacement::setLongitudeDeg (double lon_deg)
649 {
650   _lon_deg = lon_deg;
651 }
652
653 void
654 FGModelPlacement::setLatitudeDeg (double lat_deg)
655 {
656   _lat_deg = lat_deg;
657 }
658
659 void
660 FGModelPlacement::setElevationFt (double elev_ft)
661 {
662   _elev_ft = elev_ft;
663 }
664
665 void
666 FGModelPlacement::setPosition (double lon_deg, double lat_deg, double elev_ft)
667 {
668   _lon_deg = lon_deg;
669   _lat_deg = lat_deg;
670   _elev_ft = elev_ft;
671 }
672
673 void
674 FGModelPlacement::setRollDeg (double roll_deg)
675 {
676   _roll_deg = roll_deg;
677 }
678
679 void
680 FGModelPlacement::setPitchDeg (double pitch_deg)
681 {
682   _pitch_deg = pitch_deg;
683 }
684
685 void
686 FGModelPlacement::setHeadingDeg (double heading_deg)
687 {
688   _heading_deg = heading_deg;
689 }
690
691 void
692 FGModelPlacement::setOrientation (double roll_deg, double pitch_deg,
693                                   double heading_deg)
694 {
695   _roll_deg = roll_deg;
696   _pitch_deg = pitch_deg;
697   _heading_deg = heading_deg;
698 }
699
700 // end of model.cxx