]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
a2b34155a343c547df2f1f79b23cb3d6ebc49b1d
[flightgear.git] / src / Main / fg_props.cxx
1 // fg_props.cxx -- support for FlightGear properties.
2 //
3 // Written by David Megginson, started 2000.
4 //
5 // Copyright (C) 2000, 2001 David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear/compiler.h>
25 #endif
26
27 #include <simgear/misc/exception.hxx>
28
29 #include STL_IOSTREAM
30
31 #include <Autopilot/newauto.hxx>
32 #include <Aircraft/aircraft.hxx>
33 #include <Time/tmp.hxx>
34 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
35 #ifndef FG_OLD_WEATHER
36 #  include <WeatherCM/FGLocalWeatherDatabase.h>
37 #else
38 #  include <Weather/weather.hxx>
39 #endif
40 #include <Objects/matlib.hxx>
41
42 #include <GUI/gui.h>
43
44 #include "fgfs.hxx"
45 #include "fg_props.hxx"
46 #include "viewmgr.hxx"
47
48 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
49 SG_USING_STD(istream);
50 SG_USING_STD(ostream);
51 #endif
52
53 static double getWindNorth ();
54 static double getWindEast ();
55 static double getWindDown ();
56
57 // Allow the view to be set from two axes (i.e. a joystick hat)
58 // This needs to be in FGViewer itself, somehow.
59 static double axisLong = 0.0;
60 static double axisLat = 0.0;
61
62 static bool winding_ccw = false; // FIXME: temporary
63
64 static bool fdm_data_logging = false; // FIXME: temporary
65
66
67 /**
68  * Utility function.
69  */
70 static inline void
71 _set_view_from_axes ()
72 {
73                                 // Take no action when hat is centered
74   if ( ( axisLong <  0.01 ) &&
75        ( axisLong > -0.01 ) &&
76        ( axisLat  <  0.01 ) &&
77        ( axisLat  > -0.01 )
78      )
79     return;
80
81   double viewDir = 999;
82
83   /* Do all the quick and easy cases */
84   if (axisLong < 0) {           // Longitudinal axis forward
85     if (axisLat == axisLong)
86       viewDir = 45;
87     else if (axisLat == - axisLong)
88       viewDir = 315;
89     else if (axisLat == 0)
90       viewDir = 0;
91   } else if (axisLong > 0) {    // Longitudinal axis backward
92     if (axisLat == - axisLong)
93       viewDir = 135;
94     else if (axisLat == axisLong)
95       viewDir = 225;
96     else if (axisLat == 0)
97       viewDir = 180;
98   } else if (axisLong == 0) {   // Longitudinal axis neutral
99     if (axisLat < 0)
100       viewDir = 90;
101     else if (axisLat > 0)
102       viewDir = 270;
103     else return; /* And assertion failure maybe? */
104   }
105
106   /* Do all the difficult cases */
107   if ( viewDir > 900 )
108     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axisLat, -axisLong );
109   if ( viewDir < -1 ) viewDir += 360;
110
111 //  SG_LOG(SG_INPUT, SG_ALERT, "Joystick Lat=" << axisLat << "   and Long="
112 //      << axisLong << "  gave angle=" << viewDir );
113
114   globals->get_current_view()->set_goal_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
115 //   globals->get_current_view()->set_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
116 }
117
118 \f
119 ////////////////////////////////////////////////////////////////////////
120 // Default property bindings (not yet handled by any module).
121 ////////////////////////////////////////////////////////////////////////
122
123
124 /**
125  * Get the pause state of the sim.
126  */
127 static bool
128 getFreeze ()
129 {
130   return globals->get_freeze();
131 }
132
133
134 /**
135  * Set the pause state of the sim.
136  */
137 static void
138 setFreeze (bool freeze)
139 {
140   globals->set_freeze(freeze);
141 }
142
143 /**
144  * Return the current aircraft directory (UIUC) as a string.
145  */
146 static string 
147 getAircraftDir ()
148 {
149   return aircraft_dir;
150 }
151
152
153 /**
154  * Set the current aircraft directory (UIUC).
155  */
156 static void
157 setAircraftDir (string dir)
158 {
159   if (getAircraftDir() != dir) {
160     aircraft_dir = dir;
161 //     needReinit(); FIXME!!
162   }
163 }
164
165
166 /**
167  * Get the current view offset in degrees.
168  */
169 static double
170 getViewOffset ()
171 {
172   return (globals->get_current_view()
173           ->get_view_offset() * SGD_RADIANS_TO_DEGREES);
174 }
175
176
177 static void
178 setViewOffset (double offset)
179 {
180   globals->get_current_view()->set_view_offset(offset * SGD_DEGREES_TO_RADIANS);
181 }
182
183 static double
184 getGoalViewOffset ()
185 {
186   return (globals->get_current_view()
187           ->get_goal_view_offset() * SGD_RADIANS_TO_DEGREES);
188 }
189
190 static void
191 setGoalViewOffset (double offset)
192 {
193     while ( offset < 0 ) {
194         offset += 360.0;
195     }
196     while ( offset > 360.0 ) {
197         offset -= 360.0;
198     }
199     // Snap to center if we are close
200     if ( fabs(offset) < 1.0 ||  fabs(offset) > 359.0 ) {
201         offset = 0.0;
202     }
203
204     globals->get_current_view()
205         ->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS);
206 }
207
208
209 /**
210  * Pilot position offset from CG.
211  */
212 static float
213 getPilotPositionXOffset ()
214 {
215   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
216   float * offset = pilot_view->get_pilot_offset();
217   return offset[0];
218 }
219
220 static void
221 setPilotPositionXOffset (float x)
222 {
223   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
224   float * offset = pilot_view->get_pilot_offset();
225   pilot_view->set_pilot_offset(x, offset[1], offset[2]);
226 }
227
228 static float
229 getPilotPositionYOffset ()
230 {
231   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
232   float * offset = pilot_view->get_pilot_offset();
233   return offset[1];
234 }
235
236 static void
237 setPilotPositionYOffset (float y)
238 {
239   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
240   float * offset = pilot_view->get_pilot_offset();
241   pilot_view->set_pilot_offset(offset[0], y, offset[2]);
242 }
243
244 static float
245 getPilotPositionZOffset ()
246 {
247   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
248   float * offset = pilot_view->get_pilot_offset();
249   return offset[2];
250 }
251
252 static void
253 setPilotPositionZOffset (float z)
254 {
255   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
256   float * offset = pilot_view->get_pilot_offset();
257   pilot_view->set_pilot_offset(offset[0], offset[1], z);
258 }
259
260
261 /**
262  * Return the current Zulu time.
263  */
264 static string 
265 getDateString ()
266 {
267   string out;
268   char buf[64];
269   struct tm * t = globals->get_time_params()->getGmt();
270   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
271           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
272           t->tm_hour, t->tm_min, t->tm_sec);
273   out = buf;
274   return out;
275 }
276
277
278 /**
279  * Set the current Zulu time.
280  */
281 static void
282 setDateString (string date_string)
283 {
284   SGTime * st = globals->get_time_params();
285   struct tm * current_time = st->getGmt();
286   struct tm new_time;
287
288                                 // Scan for basic ISO format
289                                 // YYYY-MM-DDTHH:MM:SS
290   int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
291                    &(new_time.tm_year), &(new_time.tm_mon),
292                    &(new_time.tm_mday), &(new_time.tm_hour),
293                    &(new_time.tm_min), &(new_time.tm_sec));
294
295                                 // Be pretty picky about this, so
296                                 // that strange things don't happen
297                                 // if the save file has been edited
298                                 // by hand.
299   if (ret != 6) {
300     SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
301            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
302     return;
303   }
304
305                                 // OK, it looks like we got six
306                                 // values, one way or another.
307   new_time.tm_year -= 1900;
308   new_time.tm_mon -= 1;
309
310                                 // Now, tell flight gear to use
311                                 // the new time.  This was far
312                                 // too difficult, by the way.
313   long int warp =
314     mktime(&new_time) - mktime(current_time) + globals->get_warp();
315   double lon = current_aircraft.fdm_state->get_Longitude();
316   double lat = current_aircraft.fdm_state->get_Latitude();
317   globals->set_warp(warp);
318   st->update(lon, lat, warp);
319   fgUpdateSkyAndLightingParams();
320 }
321
322 /**
323  * Return the GMT as a string.
324  */
325 static string 
326 getGMTString ()
327 {
328   string out;
329   char buf[16];
330   struct tm * t = globals->get_time_params()->getGmt();
331   sprintf(buf, " %.2d:%.2d:%.2d",
332           t->tm_hour, t->tm_min, t->tm_sec);
333   out = buf;
334   return out;
335 }
336
337
338 /**
339  * Get the texture rendering state.
340  */
341 static bool
342 getTextures ()
343 {
344   return (material_lib.get_step() == 0);
345 }
346
347
348 /**
349  * Set the texture rendering state.
350  */
351 static void
352 setTextures (bool textures)
353 {
354   if (textures)
355     material_lib.set_step(0);
356   else
357     material_lib.set_step(1);
358 }
359
360
361 /**
362  * Return the magnetic variation
363  */
364 static double
365 getMagVar ()
366 {
367   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
368 }
369
370
371 /**
372  * Return the magnetic dip
373  */
374 static double
375 getMagDip ()
376 {
377   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
378 }
379
380
381 /**
382  * Return the current heading in degrees.
383  */
384 static double
385 getHeadingMag ()
386 {
387   return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
388 }
389
390
391 /**
392  * Return the current engine0 rpm
393  */
394 static double
395 getRPM ()
396 {
397   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
398       return current_aircraft.fdm_state->get_engine(0)->get_RPM();
399   } else {
400       return 0.0;
401   }
402 }
403
404
405 /**
406  * Return the current engine0 EGT.
407  */
408 static double
409 getEGT ()
410 {
411   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
412       return current_aircraft.fdm_state->get_engine(0)->get_EGT();
413   } else {
414       return 0.0;
415   }
416 }
417
418 /**
419  * Return the current engine0 CHT.
420  */
421 static double
422 getCHT ()
423 {
424   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
425       return current_aircraft.fdm_state->get_engine(0)->get_CHT();
426   } else {
427       return 0.0;
428   }
429 }
430
431 /**
432  * Return the current engine0 Manifold Pressure.
433  */
434 static double
435 getMP ()
436 {
437   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
438       return current_aircraft.fdm_state->get_engine(0)->get_Manifold_Pressure();
439   } else {
440       return 0.0;
441   }
442 }
443
444
445 /**
446  * Return the current engine0 fuel flow
447  */
448 static double
449 getFuelFlow ()
450 {
451   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
452       return current_aircraft.fdm_state->get_engine(0)->get_Fuel_Flow();
453   } else {
454       return 0.0;
455   }
456 }
457
458 /**
459  * Return the fuel level in tank 1
460  */
461 static double
462 getTank1Fuel ()
463 {
464   return current_aircraft.fdm_state->get_Tank1Fuel();
465 }
466
467 static void
468 setTank1Fuel ( double gals )
469 {
470   current_aircraft.fdm_state->set_Tank1Fuel( gals );
471 }
472
473 /**
474  * Return the fuel level in tank 2
475  */
476 static double
477 getTank2Fuel ()
478 {
479   return current_aircraft.fdm_state->get_Tank2Fuel();
480 }
481
482 static void
483 setTank2Fuel ( double gals )
484 {
485   current_aircraft.fdm_state->set_Tank2Fuel( gals );
486 }
487
488
489 /**
490  * Get the autopilot altitude lock (true=on).
491  */
492 static bool
493 getAPAltitudeLock ()
494 {
495     return (current_autopilot->get_AltitudeEnabled() &&
496             current_autopilot->get_AltitudeMode()
497             == FGAutopilot::FG_ALTITUDE_LOCK);
498 }
499
500
501 /**
502  * Set the autopilot altitude lock (true=on).
503  */
504 static void
505 setAPAltitudeLock (bool lock)
506 {
507   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
508   current_autopilot->set_AltitudeEnabled(lock);
509 }
510
511
512 /**
513  * Get the autopilot target altitude in feet.
514  */
515 static double
516 getAPAltitude ()
517 {
518   return current_autopilot->get_TargetAltitude() * SG_METER_TO_FEET;
519 }
520
521
522 /**
523  * Set the autopilot target altitude in feet.
524  */
525 static void
526 setAPAltitude (double altitude)
527 {
528     current_autopilot->set_TargetAltitude( altitude * SG_FEET_TO_METER );
529 }
530
531 /**
532  * Get the autopilot altitude lock (true=on).
533  */
534 static bool
535 getAPGSLock ()
536 {
537     return (current_autopilot->get_AltitudeEnabled() &&
538             (current_autopilot->get_AltitudeMode()
539              == FGAutopilot::FG_ALTITUDE_GS1));
540 }
541
542
543 /**
544  * Set the autopilot altitude lock (true=on).
545  */
546 static void
547 setAPGSLock (bool lock)
548 {
549   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_GS1);
550   current_autopilot->set_AltitudeEnabled(lock);
551 }
552
553
554 /**
555  * Get the autopilot terrain lock (true=on).
556  */
557 static bool
558 getAPTerrainLock ()
559 {
560     return (current_autopilot->get_AltitudeEnabled() &&
561             (current_autopilot->get_AltitudeMode()
562              == FGAutopilot::FG_ALTITUDE_TERRAIN));
563 }
564
565
566 /**
567  * Set the autopilot terrain lock (true=on).
568  */
569 static void
570 setAPTerrainLock (bool lock)
571 {
572   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_TERRAIN);
573   current_autopilot->set_AltitudeEnabled(lock);
574   current_autopilot->set_TargetAGL(
575       current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
576     );
577   cout << "Target AGL = "
578        << current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
579        << endl;
580 }
581
582
583 /**
584  * Get the autopilot target altitude in feet.
585  */
586 static double
587 getAPClimb ()
588 {
589   return current_autopilot->get_TargetClimbRate() * SG_METER_TO_FEET;
590 }
591
592
593 /**
594  * Set the autopilot target altitude in feet.
595  */
596 static void
597 setAPClimb (double rate)
598 {
599     current_autopilot->set_TargetClimbRate( rate * SG_FEET_TO_METER );
600 }
601
602
603 /**
604  * Get the autopilot heading lock (true=on).
605  */
606 static bool
607 getAPHeadingLock ()
608 {
609     return
610       (current_autopilot->get_HeadingEnabled() &&
611        current_autopilot->get_HeadingMode() == DEFAULT_AP_HEADING_LOCK);
612 }
613
614
615 /**
616  * Set the autopilot heading lock (true=on).
617  */
618 static void
619 setAPHeadingLock (bool lock)
620 {
621     if (lock) {
622         current_autopilot->set_HeadingMode(DEFAULT_AP_HEADING_LOCK);
623         current_autopilot->set_HeadingEnabled(true);
624     } else {
625         current_autopilot->set_HeadingEnabled(false);
626     }
627 }
628
629
630 /**
631  * Get the autopilot heading bug in degrees.
632  */
633 static double
634 getAPHeadingBug ()
635 {
636   return current_autopilot->get_DGTargetHeading();
637 }
638
639
640 /**
641  * Set the autopilot heading bug in degrees.
642  */
643 static void
644 setAPHeadingBug (double heading)
645 {
646   current_autopilot->set_DGTargetHeading( heading );
647 }
648
649
650 /**
651  * Get the autopilot wing leveler lock (true=on).
652  */
653 static bool
654 getAPWingLeveler ()
655 {
656     return
657       (current_autopilot->get_HeadingEnabled() &&
658        current_autopilot->get_HeadingMode() == FGAutopilot::FG_TC_HEADING_LOCK);
659 }
660
661
662 /**
663  * Set the autopilot wing leveler lock (true=on).
664  */
665 static void
666 setAPWingLeveler (bool lock)
667 {
668     if (lock) {
669         current_autopilot->set_HeadingMode(FGAutopilot::FG_TC_HEADING_LOCK);
670         current_autopilot->set_HeadingEnabled(true);
671     } else {
672         current_autopilot->set_HeadingEnabled(false);
673     }
674 }
675
676 /**
677  * Return true if the autopilot is locked to NAV1.
678  */
679 static bool
680 getAPNAV1Lock ()
681 {
682   return
683     (current_autopilot->get_HeadingEnabled() &&
684      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
685 }
686
687
688 /**
689  * Set the autopilot NAV1 lock.
690  */
691 static void
692 setAPNAV1Lock (bool lock)
693 {
694   if (lock) {
695     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
696     current_autopilot->set_HeadingEnabled(true);
697   } else if (current_autopilot->get_HeadingMode() ==
698              FGAutopilot::FG_HEADING_NAV1) {
699     current_autopilot->set_HeadingEnabled(false);
700   }
701 }
702
703 /**
704  * Get the autopilot autothrottle lock.
705  */
706 static bool
707 getAPAutoThrottleLock ()
708 {
709   return current_autopilot->get_AutoThrottleEnabled();
710 }
711
712
713 /**
714  * Set the autothrottle lock.
715  */
716 static void
717 setAPAutoThrottleLock (bool lock)
718 {
719   current_autopilot->set_AutoThrottleEnabled(lock);
720 }
721
722
723 // kludge
724 static double
725 getAPRudderControl ()
726 {
727     if (getAPHeadingLock())
728         return current_autopilot->get_TargetHeading();
729     else
730         return globals->get_controls()->get_rudder();
731 }
732
733 // kludge
734 static void
735 setAPRudderControl (double value)
736 {
737     if (getAPHeadingLock()) {
738         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPRudderControl " << value );
739         value -= current_autopilot->get_TargetHeading();
740         current_autopilot->HeadingAdjust(value < 0.0 ? -1.0 : 1.0);
741     } else {
742         globals->get_controls()->set_rudder(value);
743     }
744 }
745
746 // kludge
747 static double
748 getAPElevatorControl ()
749 {
750   if (getAPAltitudeLock())
751       return current_autopilot->get_TargetAltitude();
752   else
753     return globals->get_controls()->get_elevator();
754 }
755
756 // kludge
757 static void
758 setAPElevatorControl (double value)
759 {
760     if (getAPAltitudeLock()) {
761         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPElevatorControl " << value );
762         value -= current_autopilot->get_TargetAltitude();
763         current_autopilot->AltitudeAdjust(value < 0.0 ? 100.0 : -100.0);
764     } else {
765         globals->get_controls()->set_elevator(value);
766     }
767 }
768
769 // kludge
770 static double
771 getAPThrottleControl ()
772 {
773   if (getAPAutoThrottleLock())
774     return 0.0;                 // always resets
775   else
776     return globals->get_controls()->get_throttle(0);
777 }
778
779 // kludge
780 static void
781 setAPThrottleControl (double value)
782 {
783   if (getAPAutoThrottleLock())
784     current_autopilot->AutoThrottleAdjust(value < 0.0 ? -0.01 : 0.01);
785   else
786     globals->get_controls()->set_throttle(0, value);
787 }
788
789
790 /**
791  * Get the current visibility (meters).
792  */
793 static double
794 getVisibility ()
795 {
796 #ifndef FG_OLD_WEATHER
797   return WeatherDatabase->getWeatherVisibility();
798 #else
799   return current_weather.get_visibility();
800 #endif
801 }
802
803
804 /**
805  * Set the current visibility (meters).
806  */
807 static void
808 setVisibility (double visibility)
809 {
810 #ifndef FG_OLD_WEATHER
811   WeatherDatabase->setWeatherVisibility(visibility);
812 #else
813   current_weather.set_visibility(visibility);
814 #endif
815 }
816
817 /**
818  * Get the current wind north velocity (feet/second).
819  */
820 static double
821 getWindNorth ()
822 {
823   return current_aircraft.fdm_state->get_V_north_airmass();
824 }
825
826
827 /**
828  * Set the current wind north velocity (feet/second).
829  */
830 static void
831 setWindNorth (double speed)
832 {
833   current_aircraft.fdm_state
834     ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
835 }
836
837
838 /**
839  * Get the current wind east velocity (feet/second).
840  */
841 static double
842 getWindEast ()
843 {
844   return current_aircraft.fdm_state->get_V_east_airmass();
845 }
846
847
848 /**
849  * Set the current wind east velocity (feet/second).
850  */
851 static void
852 setWindEast (double speed)
853 {
854   cout << "Set wind-east to " << speed << endl;
855   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
856                                                            speed,
857                                                            getWindDown());
858 }
859
860
861 /**
862  * Get the current wind down velocity (feet/second).
863  */
864 static double
865 getWindDown ()
866 {
867   return current_aircraft.fdm_state->get_V_down_airmass();
868 }
869
870
871 /**
872  * Set the current wind down velocity (feet/second).
873  */
874 static void
875 setWindDown (double speed)
876 {
877   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
878                                                            getWindEast(),
879                                                            speed);
880 }
881
882 static double
883 getFOV ()
884 {
885   return globals->get_current_view()->get_fov();
886 }
887
888 static void
889 setFOV (double fov)
890 {
891   globals->get_current_view()->set_fov( fov );
892 }
893
894 static long
895 getWarp ()
896 {
897   return globals->get_warp();
898 }
899
900 static void
901 setWarp (long warp)
902 {
903   globals->set_warp(warp);
904 }
905
906 static long
907 getWarpDelta ()
908 {
909   return globals->get_warp_delta();
910 }
911
912 static void
913 setWarpDelta (long delta)
914 {
915   globals->set_warp_delta(delta);
916 }
917
918 static void
919 setViewAxisLong (double axis)
920 {
921   axisLong = axis;
922 }
923
924 static void
925 setViewAxisLat (double axis)
926 {
927   axisLat = axis;
928 }
929
930 static bool
931 getWindingCCW ()
932 {
933   return winding_ccw;
934 }
935
936 static void
937 setWindingCCW (bool state)
938 {
939   winding_ccw = state;
940   if ( winding_ccw )
941     glFrontFace ( GL_CCW );
942   else
943     glFrontFace ( GL_CW );
944 }
945
946 static bool
947 getFullScreen ()
948 {
949 #if defined(FX) && !defined(WIN32)
950   return global_fullscreen;
951 #else
952   return false;
953 #endif
954 }
955
956 static void
957 setFullScreen (bool state)
958 {
959 #if defined(FX) && !defined(WIN32)
960   global_fullscreen = state;
961 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
962   XMesaSetFXmode( global_fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
963 #  endif
964 #endif
965 }
966
967 static bool
968 getFDMDataLogging ()
969 {
970   return fdm_data_logging;
971 }
972
973 static void
974 setFDMDataLogging (bool state)
975 {
976                                 // kludge; no getter or setter available
977   if (state != fdm_data_logging) {
978     fgToggleFDMdataLogging();
979     fdm_data_logging = state;
980   }
981 }
982
983 \f
984 ////////////////////////////////////////////////////////////////////////
985 // Tie the properties.
986 ////////////////////////////////////////////////////////////////////////
987
988 void
989 fgInitProps ()
990 {
991                                 // Simulation
992   fgTie("/sim/freeze", getFreeze, setFreeze);
993   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
994   fgTie("/sim/view/offset-deg", getViewOffset, setViewOffset);
995   fgSetArchivable("/sim/view/offset-deg");
996   fgTie("/sim/view/goal-offset-deg", getGoalViewOffset, setGoalViewOffset);
997   fgSetArchivable("/sim/view/goal-offset-deg");
998   fgTie("/sim/view/pilot/x-offset-m",
999         getPilotPositionXOffset, setPilotPositionXOffset);
1000   fgSetArchivable("/sim/view/pilot/x-offset-m");
1001   fgTie("/sim/view/pilot/y-offset-m",
1002         getPilotPositionYOffset, setPilotPositionYOffset);
1003   fgSetArchivable("/sim/view/pilot/y-offset-m");
1004   fgTie("/sim/view/pilot/z-offset-m",
1005         getPilotPositionZOffset, setPilotPositionZOffset);
1006   fgSetArchivable("/sim/view/pilot/z-offset-m");
1007   fgTie("/sim/time/gmt", getDateString, setDateString);
1008   fgSetArchivable("/sim/time/gmt");
1009   fgTie("/sim/time/gmt-string", getGMTString);
1010   fgTie("/sim/rendering/textures", getTextures, setTextures);
1011
1012                                 // Orientation
1013   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
1014
1015                                 // Engine
1016   fgTie("/engines/engine[0]/rpm", getRPM);
1017   fgTie("/engines/engine[0]/egt-degf", getEGT);
1018   fgTie("/engines/engine[0]/cht-degf", getCHT);
1019   fgTie("/engines/engine[0]/mp-osi", getMP);
1020   fgTie("/engines/engine[0]/fuel-flow-gph", getFuelFlow);
1021
1022   //consumables
1023   fgTie("/consumables/fuel/tank[0]/level-gal_us",
1024         getTank1Fuel, setTank1Fuel, false);
1025   fgSetArchivable("/consumables/fuel/tank[0]/level-gal_us");
1026   fgTie("/consumables/fuel/tank[1]/level-gal_us",
1027         getTank2Fuel, setTank2Fuel, false);
1028   fgSetArchivable("/consumables/fuel/tank[1]/level-gal_us");
1029
1030                                 // Autopilot
1031   fgTie("/autopilot/locks/altitude", getAPAltitudeLock, setAPAltitudeLock);
1032   fgSetArchivable("/autopilot/locks/altitude");
1033   fgTie("/autopilot/settings/altitude-ft", getAPAltitude, setAPAltitude);
1034   fgSetArchivable("/autopilot/settings/altitude-ft");
1035   fgTie("/autopilot/locks/glide-slope", getAPGSLock, setAPGSLock);
1036   fgSetArchivable("/autopilot/locks/glide-slope");
1037   fgTie("/autopilot/locks/terrain", getAPTerrainLock, setAPTerrainLock);
1038   fgSetArchivable("/autopilot/locks/terrain");
1039   fgTie("/autopilot/settings/agl-ft", getAPAltitude, setAPAltitude);
1040   fgSetArchivable("/autopilot/settings/agl-ft");
1041   fgTie("/autopilot/settings/climb-rate-fpm", getAPClimb, setAPClimb, false);
1042   fgSetArchivable("/autopilot/settings/climb-rate-fpm");
1043   fgTie("/autopilot/locks/heading", getAPHeadingLock, setAPHeadingLock);
1044   fgSetArchivable("/autopilot/locks/heading");
1045   fgTie("/autopilot/settings/heading-bug-deg",
1046         getAPHeadingBug, setAPHeadingBug, false);
1047   fgSetArchivable("/autopilot/settings/heading-bug-deg");
1048   fgTie("/autopilot/locks/wing-leveler", getAPWingLeveler, setAPWingLeveler);
1049   fgSetArchivable("/autopilot/locks/wing-leveler");
1050   fgTie("/autopilot/locks/nav[0]", getAPNAV1Lock, setAPNAV1Lock);
1051   fgSetArchivable("/autopilot/locks/nav[0]");
1052   fgTie("/autopilot/locks/auto-throttle",
1053         getAPAutoThrottleLock, setAPAutoThrottleLock);
1054   fgSetArchivable("/autopilot/locks/auto-throttle");
1055   fgTie("/autopilot/control-overrides/rudder",
1056         getAPRudderControl, setAPRudderControl);
1057   fgSetArchivable("/autopilot/control-overrides/rudder");
1058   fgTie("/autopilot/control-overrides/elevator",
1059         getAPElevatorControl, setAPElevatorControl);
1060   fgSetArchivable("/autopilot/control-overrides/elevator");
1061   fgTie("/autopilot/control-overrides/throttle",
1062         getAPThrottleControl, setAPThrottleControl);
1063   fgSetArchivable("/autopilot/control-overrides/throttle");
1064
1065                                 // Environment
1066   fgTie("/environment/visibility-m", getVisibility, setVisibility);
1067   fgSetArchivable("/environment/visibility-m");
1068   fgTie("/environment/wind-north-fps", getWindNorth, setWindNorth);
1069   fgSetArchivable("/environment/wind-north-fps");
1070   fgTie("/environment/wind-east-fps", getWindEast, setWindEast);
1071   fgSetArchivable("/environment/wind-east-fps");
1072   fgTie("/environment/wind-down-fps", getWindDown, setWindDown);
1073   fgSetArchivable("/environment/wind-down-fps");
1074
1075   fgTie("/environment/magnetic-variation-deg", getMagVar);
1076   fgTie("/environment/magnetic-dip-deg", getMagDip);
1077
1078                                 // View
1079   fgTie("/sim/field-of-view", getFOV, setFOV);
1080   fgSetArchivable("/sim/field-of-view");
1081   fgTie("/sim/time/warp", getWarp, setWarp, false);
1082   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
1083   fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
1084   fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
1085
1086                                 // Misc. Temporary junk.
1087   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW);
1088   fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
1089   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
1090         
1091 }
1092
1093
1094 void
1095 fgUpdateProps ()
1096 {
1097   _set_view_from_axes();
1098 }
1099
1100
1101 \f
1102 ////////////////////////////////////////////////////////////////////////
1103 // Save and restore.
1104 ////////////////////////////////////////////////////////////////////////
1105
1106
1107 /**
1108  * Save the current state of the simulator to a stream.
1109  */
1110 bool
1111 fgSaveFlight (ostream &output)
1112 {
1113   try {
1114     writeProperties(output, globals->get_props());
1115   } catch (const sg_exception &e) {
1116     guiErrorMessage("Error saving flight: ", e);
1117     return false;
1118   }
1119   return true;
1120 }
1121
1122
1123 /**
1124  * Restore the current state of the simulator from a stream.
1125  */
1126 bool
1127 fgLoadFlight (istream &input)
1128 {
1129   SGPropertyNode props;
1130   try {
1131     readProperties(input, &props);
1132   } catch (const sg_exception &e) {
1133     guiErrorMessage("Error reading saved flight: ", e);
1134     return false;
1135   }
1136   copyProperties(&props, globals->get_props());
1137   // When loading a flight, make it the
1138   // new initial state.
1139   globals->saveInitialState();
1140   return true;
1141 }
1142
1143
1144 \f
1145 ////////////////////////////////////////////////////////////////////////
1146 // Implementation of FGCondition.
1147 ////////////////////////////////////////////////////////////////////////
1148
1149 FGCondition::FGCondition ()
1150 {
1151 }
1152
1153 FGCondition::~FGCondition ()
1154 {
1155 }
1156
1157
1158 \f
1159 ////////////////////////////////////////////////////////////////////////
1160 // Implementation of FGPropertyCondition.
1161 ////////////////////////////////////////////////////////////////////////
1162
1163 FGPropertyCondition::FGPropertyCondition (const string &propname)
1164   : _node(fgGetNode(propname, true))
1165 {
1166 }
1167
1168 FGPropertyCondition::~FGPropertyCondition ()
1169 {
1170 }
1171
1172
1173 \f
1174 ////////////////////////////////////////////////////////////////////////
1175 // Implementation of FGNotCondition.
1176 ////////////////////////////////////////////////////////////////////////
1177
1178 FGNotCondition::FGNotCondition (FGCondition * condition)
1179   : _condition(condition)
1180 {
1181 }
1182
1183 FGNotCondition::~FGNotCondition ()
1184 {
1185   delete _condition;
1186 }
1187
1188 bool
1189 FGNotCondition::test () const
1190 {
1191   return !(_condition->test());
1192 }
1193
1194
1195 \f
1196 ////////////////////////////////////////////////////////////////////////
1197 // Implementation of FGAndCondition.
1198 ////////////////////////////////////////////////////////////////////////
1199
1200 FGAndCondition::FGAndCondition ()
1201 {
1202 }
1203
1204 FGAndCondition::~FGAndCondition ()
1205 {
1206   for (unsigned int i = 0; i < _conditions.size(); i++)
1207     delete _conditions[i];
1208 }
1209
1210 bool
1211 FGAndCondition::test () const
1212 {
1213   int nConditions = _conditions.size();
1214   for (int i = 0; i < nConditions; i++) {
1215     if (!_conditions[i]->test())
1216       return false;
1217   }
1218   return true;
1219 }
1220
1221 void
1222 FGAndCondition::addCondition (FGCondition * condition)
1223 {
1224   _conditions.push_back(condition);
1225 }
1226
1227
1228 \f
1229 ////////////////////////////////////////////////////////////////////////
1230 // Implementation of FGOrCondition.
1231 ////////////////////////////////////////////////////////////////////////
1232
1233 FGOrCondition::FGOrCondition ()
1234 {
1235 }
1236
1237 FGOrCondition::~FGOrCondition ()
1238 {
1239   for (unsigned int i = 0; i < _conditions.size(); i++)
1240     delete _conditions[i];
1241 }
1242
1243 bool
1244 FGOrCondition::test () const
1245 {
1246   int nConditions = _conditions.size();
1247   for (int i = 0; i < nConditions; i++) {
1248     if (_conditions[i]->test())
1249       return true;
1250   }
1251   return false;
1252 }
1253
1254 void
1255 FGOrCondition::addCondition (FGCondition * condition)
1256 {
1257   _conditions.push_back(condition);
1258 }
1259
1260
1261 \f
1262 ////////////////////////////////////////////////////////////////////////
1263 // Implementation of FGComparisonCondition.
1264 ////////////////////////////////////////////////////////////////////////
1265
1266 static int
1267 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
1268 {
1269   switch (left->getType()) {
1270   case SGPropertyNode::BOOL: {
1271     bool v1 = left->getBoolValue();
1272     bool v2 = right->getBoolValue();
1273     if (v1 < v2)
1274       return FGComparisonCondition::LESS_THAN;
1275     else if (v1 > v2)
1276       return FGComparisonCondition::GREATER_THAN;
1277     else
1278       return FGComparisonCondition::EQUALS;
1279     break;
1280   }
1281   case SGPropertyNode::INT: {
1282     int v1 = left->getIntValue();
1283     int v2 = right->getIntValue();
1284     if (v1 < v2)
1285       return FGComparisonCondition::LESS_THAN;
1286     else if (v1 > v2)
1287       return FGComparisonCondition::GREATER_THAN;
1288     else
1289       return FGComparisonCondition::EQUALS;
1290     break;
1291   }
1292   case SGPropertyNode::LONG: {
1293     long v1 = left->getLongValue();
1294     long v2 = right->getLongValue();
1295     if (v1 < v2)
1296       return FGComparisonCondition::LESS_THAN;
1297     else if (v1 > v2)
1298       return FGComparisonCondition::GREATER_THAN;
1299     else
1300       return FGComparisonCondition::EQUALS;
1301     break;
1302   }
1303   case SGPropertyNode::FLOAT: {
1304     float v1 = left->getFloatValue();
1305     float v2 = right->getFloatValue();
1306     if (v1 < v2)
1307       return FGComparisonCondition::LESS_THAN;
1308     else if (v1 > v2)
1309       return FGComparisonCondition::GREATER_THAN;
1310     else
1311       return FGComparisonCondition::EQUALS;
1312     break;
1313   }
1314   case SGPropertyNode::DOUBLE: {
1315     double v1 = left->getDoubleValue();
1316     double v2 = right->getDoubleValue();
1317     if (v1 < v2)
1318       return FGComparisonCondition::LESS_THAN;
1319     else if (v1 > v2)
1320       return FGComparisonCondition::GREATER_THAN;
1321     else
1322       return FGComparisonCondition::EQUALS;
1323     break;
1324   }
1325   case SGPropertyNode::STRING: 
1326   case SGPropertyNode::NONE:
1327   case SGPropertyNode::UNSPECIFIED: {
1328     string v1 = left->getStringValue();
1329     string v2 = right->getStringValue();
1330     if (v1 < v2)
1331       return FGComparisonCondition::LESS_THAN;
1332     else if (v1 > v2)
1333       return FGComparisonCondition::GREATER_THAN;
1334     else
1335       return FGComparisonCondition::EQUALS;
1336     break;
1337   }
1338   }
1339   throw sg_exception("Unrecognized node type");
1340   return 0;
1341 }
1342
1343
1344 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1345   : _type(type),
1346     _reverse(reverse),
1347     _left_property(0),
1348     _right_property(0),
1349     _right_value(0)
1350 {
1351 }
1352
1353 FGComparisonCondition::~FGComparisonCondition ()
1354 {
1355   delete _right_value;
1356 }
1357
1358 bool
1359 FGComparisonCondition::test () const
1360 {
1361                                 // Always fail if incompletely specified
1362   if (_left_property == 0 ||
1363       (_right_property == 0 && _right_value == 0))
1364     return false;
1365
1366                                 // Get LESS_THAN, EQUALS, or GREATER_THAN
1367   int cmp =
1368     doComparison(_left_property,
1369                  (_right_property != 0 ? _right_property : _right_value));
1370   if (!_reverse)
1371     return (cmp == _type);
1372   else
1373     return (cmp != _type);
1374 }
1375
1376 void
1377 FGComparisonCondition::setLeftProperty (const string &propname)
1378 {
1379   _left_property = fgGetNode(propname, true);
1380 }
1381
1382 void
1383 FGComparisonCondition::setRightProperty (const string &propname)
1384 {
1385   delete _right_value;
1386   _right_value = 0;
1387   _right_property = fgGetNode(propname, true);
1388 }
1389
1390 void
1391 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1392 {
1393   _right_property = 0;
1394   delete _right_value;
1395   _right_value = new SGPropertyNode(*node);
1396 }
1397
1398
1399 \f
1400 ////////////////////////////////////////////////////////////////////////
1401 // Read a condition and use it if necessary.
1402 ////////////////////////////////////////////////////////////////////////
1403
1404                                 // Forward declaration
1405 static FGCondition * readCondition (const SGPropertyNode * node);
1406
1407 static FGCondition *
1408 readPropertyCondition (const SGPropertyNode * node)
1409 {
1410   return new FGPropertyCondition(node->getStringValue());
1411 }
1412
1413 static FGCondition *
1414 readNotCondition (const SGPropertyNode * node)
1415 {
1416   int nChildren = node->nChildren();
1417   for (int i = 0; i < nChildren; i++) {
1418     const SGPropertyNode * child = node->getChild(i);
1419     FGCondition * condition = readCondition(child);
1420     if (condition != 0)
1421       return new FGNotCondition(condition);
1422   }
1423   SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1424   return 0;
1425 }
1426
1427 static FGCondition *
1428 readAndConditions (const SGPropertyNode * node)
1429 {
1430   FGAndCondition * andCondition = new FGAndCondition;
1431   int nChildren = node->nChildren();
1432   for (int i = 0; i < nChildren; i++) {
1433     const SGPropertyNode * child = node->getChild(i);
1434     FGCondition * condition = readCondition(child);
1435     if (condition != 0)
1436       andCondition->addCondition(condition);
1437   }
1438   return andCondition;
1439 }
1440
1441 static FGCondition *
1442 readOrConditions (const SGPropertyNode * node)
1443 {
1444   FGOrCondition * orCondition = new FGOrCondition;
1445   int nChildren = node->nChildren();
1446   for (int i = 0; i < nChildren; i++) {
1447     const SGPropertyNode * child = node->getChild(i);
1448     FGCondition * condition = readCondition(child);
1449     if (condition != 0)
1450       orCondition->addCondition(condition);
1451   }
1452   return orCondition;
1453 }
1454
1455 static FGCondition *
1456 readComparison (const SGPropertyNode * node,
1457                 FGComparisonCondition::Type type,
1458                 bool reverse)
1459 {
1460   FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1461   condition->setLeftProperty(node->getStringValue("property[0]"));
1462   if (node->hasValue("property[1]"))
1463     condition->setRightProperty(node->getStringValue("property[1]"));
1464   else
1465     condition->setRightValue(node->getChild("value", 0));
1466
1467   return condition;
1468 }
1469
1470 static FGCondition *
1471 readCondition (const SGPropertyNode * node)
1472 {
1473   const string &name = node->getName();
1474   if (name == "property")
1475     return readPropertyCondition(node);
1476   else if (name == "not")
1477     return readNotCondition(node);
1478   else if (name == "and")
1479     return readAndConditions(node);
1480   else if (name == "or")
1481     return readOrConditions(node);
1482   else if (name == "less-than")
1483     return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1484   else if (name == "less-than-equals")
1485     return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1486   else if (name == "greater-than")
1487     return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1488   else if (name == "greater-than-equals")
1489     return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1490   else if (name == "equals")
1491     return readComparison(node, FGComparisonCondition::EQUALS, false);
1492   else if (name == "not-equals")
1493     return readComparison(node, FGComparisonCondition::EQUALS, true);
1494   else
1495     return 0;
1496 }
1497
1498
1499 \f
1500 ////////////////////////////////////////////////////////////////////////
1501 // Implementation of FGConditional.
1502 ////////////////////////////////////////////////////////////////////////
1503
1504 FGConditional::FGConditional ()
1505   : _condition (0)
1506 {
1507 }
1508
1509 FGConditional::~FGConditional ()
1510 {
1511   delete _condition;
1512 }
1513
1514 void
1515 FGConditional::setCondition (FGCondition * condition)
1516 {
1517   delete _condition;
1518   _condition = condition;
1519 }
1520
1521 bool
1522 FGConditional::test () const
1523 {
1524   return ((_condition == 0) || _condition->test());
1525 }
1526
1527
1528 \f
1529 // The top-level is always an implicit 'and' group
1530 FGCondition *
1531 fgReadCondition (const SGPropertyNode * node)
1532 {
1533   return readAndConditions(node);
1534 }
1535
1536
1537 // end of fg_props.cxx