]> git.mxchange.org Git - flightgear.git/blob - src/Main/viewmgr.cxx
Work around a problem in certain NVidia adapters hat don't support fgPushAttrib(FG_FO...
[flightgear.git] / src / Main / viewmgr.cxx
1 // viewmgr.cxx -- class for managing all the views in the flightgear world.
2 //
3 // Written by Curtis Olson, started October 2000.
4 //   partially rewritten by Jim Wilson March 2002
5 //
6 // Copyright (C) 2000  Curtis L. Olson  - curt@flightgear.org
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24 #include <string.h>             // strcmp
25
26 #include <plib/sg.h>
27
28 #include "viewmgr.hxx"
29 #include "fg_props.hxx"
30
31
32 // Constructor
33 FGViewMgr::FGViewMgr( void ) :
34   axis_long(0),
35   axis_lat(0),
36   current(0)
37 {
38 }
39
40
41 // Destructor
42 FGViewMgr::~FGViewMgr( void ) {
43 }
44
45 void
46 FGViewMgr::init ()
47 {
48   char stridx [ 20 ];
49   string viewpath, nodepath, strdata;
50   bool from_model = false;
51   bool at_model = false;
52   int from_model_index = 0;
53   int at_model_index = 0;
54   double damp_alt, damp_roll, damp_pitch, damp_heading;
55   double x_offset_m, y_offset_m, z_offset_m, fov_deg;
56   double heading_offset_deg, pitch_offset_deg, roll_offset_deg;
57   double target_x_offset_m, target_y_offset_m, target_z_offset_m;
58   double near_m;
59
60   for (int i = 0; i < fgGetInt("/sim/number-views"); i++) {
61     viewpath = "/sim/view";
62     sprintf(stridx, "[%d]", i);
63     viewpath += stridx;
64
65     // find out what type of view this is...
66     nodepath = viewpath;
67     nodepath += "/type";
68     strdata = fgGetString(nodepath.c_str());
69
70     // FIXME:
71     // this is assumed to be an aircraft model...we will need to read
72     // model-from-type as well.
73     // find out if this is a model we are looking from...
74     nodepath = viewpath;
75     nodepath += "/config/from-model";
76     from_model = fgGetBool(nodepath.c_str());
77
78     // get model index (which model)
79     if (from_model) {
80       nodepath = viewpath;
81       nodepath += "/config/from-model-idx";
82       from_model_index = fgGetInt(nodepath.c_str());     
83     }
84
85     if ( strcmp("lookat",strdata.c_str()) == 0 ) {
86       // find out if this is a model we are looking at...
87       nodepath = viewpath;
88       nodepath += "/config/at-model";
89       at_model = fgGetBool(nodepath.c_str());
90
91       // get model index (which model)
92       if (at_model) {
93         nodepath = viewpath;
94         nodepath += "/config/at-model-idx";
95         at_model_index = fgGetInt(nodepath.c_str());
96
97         nodepath = viewpath;
98         nodepath += "/config/at-model-roll-damping";
99         damp_roll = fgGetDouble(nodepath.c_str(), 0.0);
100         nodepath = viewpath;
101         nodepath += "/config/at-model-pitch-damping";
102         damp_pitch = fgGetDouble(nodepath.c_str(), 0.0);
103         nodepath = viewpath;
104         nodepath += "/config/at-model-heading-damping";
105         damp_heading = fgGetDouble(nodepath.c_str(), 0.0);
106       }
107     }
108
109     nodepath = viewpath;
110     nodepath += "/config/x-offset-m";
111     x_offset_m = fgGetDouble(nodepath.c_str());
112     nodepath = viewpath;
113     nodepath += "/config/y-offset-m";
114     y_offset_m = fgGetDouble(nodepath.c_str());
115     nodepath = viewpath;
116     nodepath += "/config/z-offset-m";
117     z_offset_m = fgGetDouble(nodepath.c_str());
118     nodepath = viewpath;
119     nodepath += "/config/pitch-offset-deg";
120     pitch_offset_deg = fgGetDouble(nodepath.c_str());
121     fgSetDouble(nodepath.c_str(),pitch_offset_deg);
122     nodepath = viewpath;
123     nodepath += "/config/heading-offset-deg";
124     heading_offset_deg = fgGetDouble(nodepath.c_str());
125     fgSetDouble(nodepath.c_str(),heading_offset_deg);
126     nodepath = viewpath;
127     nodepath += "/config/roll-offset-deg";
128     roll_offset_deg = fgGetDouble(nodepath.c_str());
129     fgSetDouble(nodepath.c_str(),roll_offset_deg);
130     nodepath = viewpath;
131     nodepath += "/config/default-field-of-view-deg";
132     fov_deg = fgGetDouble(nodepath.c_str());
133
134     // target offsets for lookat mode only...
135     nodepath = viewpath;
136     nodepath += "/config/target-x-offset-m";
137     target_x_offset_m = fgGetDouble(nodepath.c_str());
138     nodepath = viewpath;
139     nodepath += "/config/target-y-offset-m";
140     target_y_offset_m = fgGetDouble(nodepath.c_str());
141     nodepath = viewpath;
142     nodepath += "/config/target-z-offset-m";
143     target_z_offset_m = fgGetDouble(nodepath.c_str());
144
145     nodepath = viewpath;
146     nodepath += "/config/ground-level-nearplane-m";
147     near_m = fgGetDouble(nodepath.c_str());
148
149     // supporting two types now "lookat" = 1 and "lookfrom" = 0
150     if ( strcmp("lookat",strdata.c_str()) == 0 )
151       add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
152                               at_model, at_model_index,
153                               damp_roll, damp_pitch, damp_heading,
154                               x_offset_m, y_offset_m,z_offset_m,
155                               heading_offset_deg, pitch_offset_deg,
156                               roll_offset_deg, fov_deg,
157                               target_x_offset_m, target_y_offset_m,
158                               target_z_offset_m, near_m ));
159     else
160       add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index,
161                               false, 0, 0.0, 0.0, 0.0,
162                               x_offset_m, y_offset_m, z_offset_m,
163                               heading_offset_deg, pitch_offset_deg,
164                               roll_offset_deg, fov_deg, 0, 0, 0, near_m ));
165   }
166
167   copyToCurrent();
168   
169 }
170
171 void
172 FGViewMgr::reinit ()
173 {
174   char stridx [ 20 ];
175   string viewpath, nodepath, strdata;
176   double fov_deg;
177
178   // reset offsets and fov to configuration defaults
179
180   for (int i = 0; i < fgGetInt("/sim/number-views"); i++) {
181     viewpath = "/sim/view";
182     sprintf(stridx, "[%d]", i);
183     viewpath += stridx;
184
185     setView(i);
186
187     nodepath = viewpath;
188     nodepath += "/config/x-offset-m";
189     fgSetDouble("/sim/current-view/x-offset-m",fgGetDouble(nodepath.c_str()));
190
191     nodepath = viewpath;
192     nodepath += "/config/y-offset-m";
193     fgSetDouble("/sim/current-view/y-offset-m",fgGetDouble(nodepath.c_str()));
194
195     nodepath = viewpath;
196     nodepath += "/config/z-offset-m";
197     fgSetDouble("/sim/current-view/z-offset-m",fgGetDouble(nodepath.c_str()));
198
199     nodepath = viewpath;
200     nodepath += "/config/pitch-offset-deg";
201     fgSetDouble("/sim/current-view/pitch-offset-deg",
202                 fgGetDouble(nodepath.c_str()));
203
204     nodepath = viewpath;
205     nodepath += "/config/heading-offset-deg";
206     fgSetDouble("/sim/current-view/heading-offset-deg",
207                 fgGetDouble(nodepath.c_str()));
208
209     nodepath = viewpath;
210     nodepath += "/config/roll-offset-deg";
211     fgSetDouble("/sim/current-view/roll-offset-deg",
212                 fgGetDouble(nodepath.c_str()));
213
214     nodepath = viewpath;
215     nodepath += "/config/default-field-of-view-deg";
216     fov_deg = fgGetDouble(nodepath.c_str());
217     if (fov_deg < 10.0) {
218       fov_deg = 55.0;
219     }
220     fgSetDouble("/sim/current-view/field-of-view",fov_deg);
221
222     // target offsets for lookat mode only...
223     nodepath = viewpath;
224     nodepath += "/config/target-x-offset-m";
225     fgSetDouble("/sim/current-view/target-x-offset-deg",
226                 fgGetDouble(nodepath.c_str()));
227
228     nodepath = viewpath;
229     nodepath += "/config/target-y-offset-m";
230     fgSetDouble("/sim/current-view/target-y-offset-deg",
231                 fgGetDouble(nodepath.c_str()));
232
233     nodepath = viewpath;
234     nodepath += "/config/target-z-offset-m";
235     fgSetDouble("/sim/current-view/target-z-offset-deg",
236                 fgGetDouble(nodepath.c_str()));
237
238  }
239
240     setView(0);
241
242 }
243
244 typedef double (FGViewMgr::*double_getter)() const;
245
246 void
247 FGViewMgr::bind ()
248 {
249   // these are bound to the current view properties
250   fgTie("/sim/current-view/heading-offset-deg", this,
251         &FGViewMgr::getViewHeadingOffset_deg,
252         &FGViewMgr::setViewHeadingOffset_deg);
253   fgSetArchivable("/sim/current-view/heading-offset-deg");
254   fgTie("/sim/current-view/goal-heading-offset-deg", this,
255         &FGViewMgr::getViewGoalHeadingOffset_deg,
256         &FGViewMgr::setViewGoalHeadingOffset_deg);
257   fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
258   fgTie("/sim/current-view/pitch-offset-deg", this,
259         &FGViewMgr::getViewPitchOffset_deg,
260         &FGViewMgr::setViewPitchOffset_deg);
261   fgSetArchivable("/sim/current-view/pitch-offset-deg");
262   fgTie("/sim/current-view/goal-pitch-offset-deg", this,
263         &FGViewMgr::getGoalViewPitchOffset_deg,
264         &FGViewMgr::setGoalViewPitchOffset_deg);
265   fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
266
267   fgTie("/sim/current-view/view-number", this, 
268                       &FGViewMgr::getView, &FGViewMgr::setView);
269   fgSetArchivable("/sim/current-view/view-number", FALSE);
270
271   fgTie("/sim/current-view/axes/long", this,
272         (double_getter)0, &FGViewMgr::setViewAxisLong);
273   fgSetArchivable("/sim/current-view/axes/long");
274
275   fgTie("/sim/current-view/axes/lat", this,
276         (double_getter)0, &FGViewMgr::setViewAxisLat);
277   fgSetArchivable("/sim/current-view/axes/lat");
278
279   fgTie("/sim/current-view/field-of-view", this,
280         &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
281   fgSetArchivable("/sim/current-view/field-of-view");
282
283   fgTie("/sim/current-view/ground-level-nearplane-m", this,
284         &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
285   fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
286
287 }
288
289 void
290 FGViewMgr::unbind ()
291 {
292   // FIXME:
293   // need to redo these bindings to the new locations (move to viewer?)
294   fgUntie("/sim/current-view/heading-offset-deg");
295   fgUntie("/sim/current-view/goal-heading-offset-deg");
296   fgUntie("/sim/current-view/pitch-offset-deg");
297   fgUntie("/sim/current-view/goal-pitch-offset-deg");
298   fgUntie("/sim/field-of-view");
299   fgUntie("/sim/current-view/view-number");
300   fgUntie("/sim/current-view/axes/long");
301   fgUntie("/sim/current-view/axes/lat");
302   fgUntie("/sim/current-view/ground-level-nearplane-m");
303 }
304
305 void
306 FGViewMgr::update (double dt)
307 {
308   char stridx [20];
309   string viewpath, nodepath;
310   double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
311
312   FGViewer * view = get_current_view();
313   if (view == 0)
314     return;
315
316   // 
317   int i = current;
318   viewpath = "/sim/view";
319   sprintf(stridx, "[%d]", i);
320   viewpath += stridx;
321
322   FGViewer *loop_view = (FGViewer *)get_view( i );
323
324                 // Set up view location and orientation
325
326   nodepath = viewpath;
327   nodepath += "/config/from-model";
328   if (!fgGetBool(nodepath.c_str())) {
329     nodepath = viewpath;
330     nodepath += "/config/eye-lon-deg-path";
331     lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
332     nodepath = viewpath;
333     nodepath += "/config/eye-lat-deg-path";
334     lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
335     nodepath = viewpath;
336     nodepath += "/config/eye-alt-ft-path";
337     alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
338     nodepath = viewpath;
339     nodepath += "/config/eye-roll-deg-path";
340     roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
341     nodepath = viewpath;
342     nodepath += "/config/eye-pitch-deg-path";
343     pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
344     nodepath = viewpath;
345     nodepath += "/config/eye-heading-deg-path";
346     heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
347     loop_view->setPosition(lon_deg, lat_deg, alt_ft);
348     loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
349   } else {
350     // force recalc in viewer
351     loop_view->set_dirty();
352   }
353
354   // if lookat (type 1) then get target data...
355   if (loop_view->getType() == FG_LOOKAT) {
356     nodepath = viewpath;
357     nodepath += "/config/from-model";
358     if (!fgGetBool(nodepath.c_str())) {
359       nodepath = viewpath;
360       nodepath += "/config/target-lon-deg-path";
361       lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
362       nodepath = viewpath;
363       nodepath += "/config/target-lat-deg-path";
364       lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
365       nodepath = viewpath;
366       nodepath += "/config/target-alt-ft-path";
367       alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
368       nodepath = viewpath;
369       nodepath += "/config/target-roll-deg-path";
370       roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
371       nodepath = viewpath;
372       nodepath += "/config/target-pitch-deg-path";
373       pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
374       nodepath = viewpath;
375       nodepath += "/config/target-heading-deg-path";
376       heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
377
378       loop_view->setTargetPosition(lon_deg, lat_deg, alt_ft);
379       loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
380     } else {
381       loop_view->set_dirty();
382     }
383   }
384
385   setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
386   setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
387   setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
388
389   setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
390   setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
391   setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
392
393                                 // Update the current view
394   do_axes();
395   view->update(dt);
396 }
397
398 void
399 FGViewMgr::copyToCurrent()
400 {
401     char stridx [20];
402     string viewpath, nodepath;
403
404     int i = current;
405     viewpath = "/sim/view";
406     sprintf(stridx, "[%d]", i);
407     viewpath += stridx;
408
409     // copy certain view config data for default values
410     nodepath = viewpath;
411     nodepath += "/config/default-heading-offset-deg";
412     fgSetDouble("/sim/current-view/config/heading-offset-deg",
413                 fgGetDouble(nodepath.c_str()));
414
415     nodepath = viewpath;
416     nodepath += "/config/pitch-offset-deg";
417     fgSetDouble("/sim/current-view/config/pitch-offset-deg",
418                 fgGetDouble(nodepath.c_str()));
419
420     nodepath = viewpath;
421     nodepath += "/config/roll-offset-deg";
422     fgSetDouble("/sim/current-view/config/roll-offset-deg",
423                 fgGetDouble(nodepath.c_str()));
424
425     nodepath = viewpath;
426     nodepath += "/config/default-field-of-view-deg";
427     fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
428                 fgGetDouble(nodepath.c_str()));
429
430     // copy view data
431     fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
432     fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
433     fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
434     fgSetDouble("/sim/current-view/goal-heading-offset-deg",
435                 get_current_view()->getGoalHeadingOffset_deg());
436     fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
437                 get_current_view()->getGoalPitchOffset_deg());
438     fgSetDouble("/sim/current-view/goal-roll-offset-deg",
439                 get_current_view()->getRollOffset_deg());
440     fgSetDouble("/sim/current-view/heading-offset-deg",
441                 get_current_view()->getHeadingOffset_deg());
442     fgSetDouble("/sim/current-view/pitch-offset-deg",
443                 get_current_view()->getPitchOffset_deg());
444     fgSetDouble("/sim/current-view/roll-offset-deg",
445                 get_current_view()->getRollOffset_deg());
446     fgSetDouble("/sim/current-view/target-x-offset-m",
447                 get_current_view()->getTargetXOffset_m());
448     fgSetDouble("/sim/current-view/target-y-offset-m",
449                 get_current_view()->getTargetYOffset_m());
450     fgSetDouble("/sim/current-view/target-z-offset-m",
451                 get_current_view()->getTargetZOffset_m());
452 }
453
454
455 double
456 FGViewMgr::getViewHeadingOffset_deg () const
457 {
458   const FGViewer * view = get_current_view();
459   return (view == 0 ? 0 : view->getHeadingOffset_deg());
460 }
461
462 void
463 FGViewMgr::setViewHeadingOffset_deg (double offset)
464 {
465   FGViewer * view = get_current_view();
466   if (view != 0) {
467     view->setGoalHeadingOffset_deg(offset);
468     view->setHeadingOffset_deg(offset);
469   }
470 }
471
472 double
473 FGViewMgr::getViewGoalHeadingOffset_deg () const
474 {
475   const FGViewer * view = get_current_view();
476   return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
477 }
478
479 void
480 FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
481 {
482   FGViewer * view = get_current_view();
483   if (view != 0)
484     view->setGoalHeadingOffset_deg(offset);
485 }
486
487 double
488 FGViewMgr::getViewPitchOffset_deg () const
489 {
490   const FGViewer * view = get_current_view();
491   return (view == 0 ? 0 : view->getPitchOffset_deg());
492 }
493
494 void
495 FGViewMgr::setViewPitchOffset_deg (double tilt)
496 {
497   FGViewer * view = get_current_view();
498   if (view != 0) {
499     view->setGoalPitchOffset_deg(tilt);
500     view->setPitchOffset_deg(tilt);
501   }
502 }
503
504 double
505 FGViewMgr::getGoalViewPitchOffset_deg () const
506 {
507   const FGViewer * view = get_current_view();
508   return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
509 }
510
511 void
512 FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
513 {
514   FGViewer * view = get_current_view();
515   if (view != 0)
516     view->setGoalPitchOffset_deg(tilt);
517 }
518
519 double
520 FGViewMgr::getViewXOffset_m () const
521 {
522   const FGViewer * view = get_current_view();
523   if (view != 0) {
524     return ((FGViewer *)view)->getXOffset_m();
525   } else {
526     return 0;
527   }
528 }
529
530 void
531 FGViewMgr::setViewXOffset_m (double x)
532 {
533   FGViewer * view = get_current_view();
534   if (view != 0) {
535     view->setXOffset_m(x);
536   }
537 }
538
539 double
540 FGViewMgr::getViewYOffset_m () const
541 {
542   const FGViewer * view = get_current_view();
543   if (view != 0) {
544     return ((FGViewer *)view)->getYOffset_m();
545   } else {
546     return 0;
547   }
548 }
549
550 void
551 FGViewMgr::setViewYOffset_m (double y)
552 {
553   FGViewer * view = get_current_view();
554   if (view != 0) {
555     view->setYOffset_m(y);
556   }
557 }
558
559 double
560 FGViewMgr::getViewZOffset_m () const
561 {
562   const FGViewer * view = get_current_view();
563   if (view != 0) {
564     return ((FGViewer *)view)->getZOffset_m();
565   } else {
566     return 0;
567   }
568 }
569
570 void
571 FGViewMgr::setViewZOffset_m (double z)
572 {
573   FGViewer * view = get_current_view();
574   if (view != 0) {
575     view->setZOffset_m(z);
576   }
577 }
578
579 double
580 FGViewMgr::getViewTargetXOffset_m () const
581 {
582   const FGViewer * view = get_current_view();
583   if (view != 0) {
584     return ((FGViewer *)view)->getTargetXOffset_m();
585   } else {
586     return 0;
587   }
588 }
589
590 void
591 FGViewMgr::setViewTargetXOffset_m (double x)
592 {
593   FGViewer * view = get_current_view();
594   if (view != 0) {
595     view->setTargetXOffset_m(x);
596   }
597 }
598
599 double
600 FGViewMgr::getViewTargetYOffset_m () const
601 {
602   const FGViewer * view = get_current_view();
603   if (view != 0) {
604     return ((FGViewer *)view)->getTargetYOffset_m();
605   } else {
606     return 0;
607   }
608 }
609
610 void
611 FGViewMgr::setViewTargetYOffset_m (double y)
612 {
613   FGViewer * view = get_current_view();
614   if (view != 0) {
615     view->setTargetYOffset_m(y);
616   }
617 }
618
619 double
620 FGViewMgr::getViewTargetZOffset_m () const
621 {
622   const FGViewer * view = get_current_view();
623   if (view != 0) {
624     return ((FGViewer *)view)->getTargetZOffset_m();
625   } else {
626     return 0;
627   }
628 }
629
630 void
631 FGViewMgr::setViewTargetZOffset_m (double z)
632 {
633   FGViewer * view = get_current_view();
634   if (view != 0) {
635     view->setTargetZOffset_m(z);
636   }
637 }
638
639 int
640 FGViewMgr::getView () const
641 {
642   return ( current );
643 }
644
645 void
646 FGViewMgr::setView (int newview )
647 {
648   // if newview number too low wrap to last view...
649   if ( newview < 0 ) {
650     newview = (int)views.size() -1;
651   }
652   // if newview number to high wrap to zero...
653   if ( newview > ((int)views.size() -1) ) {
654     newview = 0;
655   }
656   // set new view
657   set_view( newview );
658   // copy in view data
659   copyToCurrent ();
660 }
661
662
663 double
664 FGViewMgr::getFOV_deg () const
665 {
666   const FGViewer * view = get_current_view();
667   return (view == 0 ? 0 : view->get_fov());
668 }
669
670 void
671 FGViewMgr::setFOV_deg (double fov)
672 {
673   FGViewer * view = get_current_view();
674   if (view != 0)
675     view->set_fov(fov);
676 }
677
678 double
679 FGViewMgr::getNear_m () const
680 {
681   const FGViewer * view = get_current_view();
682   return (view == 0 ? 0.5f : view->getNear_m());
683 }
684
685 void
686 FGViewMgr::setNear_m (double near_m)
687 {
688   FGViewer * view = get_current_view();
689   if (view != 0)
690     view->setNear_m(near_m);
691 }
692
693 void
694 FGViewMgr::setViewAxisLong (double axis)
695 {
696   axis_long = axis;
697 }
698
699 void
700 FGViewMgr::setViewAxisLat (double axis)
701 {
702   axis_lat = axis;
703 }
704
705 void
706 FGViewMgr::do_axes ()
707 {
708                                 // Take no action when hat is centered
709   if ( ( axis_long <  0.01 ) &&
710        ( axis_long > -0.01 ) &&
711        ( axis_lat  <  0.01 ) &&
712        ( axis_lat  > -0.01 )
713      )
714     return;
715
716   double viewDir = 999;
717
718   /* Do all the quick and easy cases */
719   if (axis_long < 0) {          // Longitudinal axis forward
720     if (axis_lat == axis_long)
721       viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
722     else if (axis_lat == - axis_long)
723       viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
724     else if (axis_lat == 0)
725       viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
726   } else if (axis_long > 0) {   // Longitudinal axis backward
727     if (axis_lat == - axis_long)
728       viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
729     else if (axis_lat == axis_long)
730       viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
731     else if (axis_lat == 0)
732       viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
733   } else if (axis_long == 0) {  // Longitudinal axis neutral
734     if (axis_lat < 0)
735       viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
736     else if (axis_lat > 0)
737       viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
738     else return; /* And assertion failure maybe? */
739   }
740
741                                 // Do all the difficult cases
742   if ( viewDir > 900 )
743     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
744   if ( viewDir < -1 ) viewDir += 360;
745
746   get_current_view()->setGoalHeadingOffset_deg(viewDir);
747 }