]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
Disable two sided light model because Andy's patch to plib makes it unneeded. This...
[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/structure/exception.hxx>
28 #include <simgear/magvar/magvar.hxx>
29 #include <simgear/timing/sg_time.hxx>
30 #include <simgear/misc/sg_path.hxx>
31 #include <simgear/scene/material/matlib.hxx>
32 #include <simgear/sound/soundmgr.hxx>
33
34 #include STL_IOSTREAM
35
36 #include <ATC/ATCdisplay.hxx>
37 #include <Aircraft/aircraft.hxx>
38 #include <Time/tmp.hxx>
39 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
40 #ifdef FG_WEATHERCM
41 #  include <WeatherCM/FGLocalWeatherDatabase.h>
42 #else
43 #  include <Environment/environment.hxx>
44 #endif // FG_WEATHERCM
45
46 #include <GUI/gui.h>
47
48 #include "globals.hxx"
49 #include "fg_props.hxx"
50
51 SG_USING_STD(istream);
52 SG_USING_STD(ostream);
53
54 #ifdef FG_WEATHERCM
55 static double getWindNorth ();
56 static double getWindEast ();
57 static double getWindDown ();
58 #endif // FG_WEATHERCM
59
60 static bool winding_ccw = true; // FIXME: temporary
61
62 static bool fdm_data_logging = false; // FIXME: temporary
63
64 static bool frozen = false;     // FIXME: temporary
65
66
67 \f
68 ////////////////////////////////////////////////////////////////////////
69 // Default property bindings (not yet handled by any module).
70 ////////////////////////////////////////////////////////////////////////
71
72 struct LogClassMapping {
73   sgDebugClass c;
74   string name;
75   LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
76 };
77
78 LogClassMapping log_class_mappings [] = {
79   LogClassMapping(SG_NONE, "none"),
80   LogClassMapping(SG_TERRAIN, "terrain"),
81   LogClassMapping(SG_ASTRO, "astro"),
82   LogClassMapping(SG_FLIGHT, "flight"),
83   LogClassMapping(SG_INPUT, "input"),
84   LogClassMapping(SG_GL, "gl"),
85   LogClassMapping(SG_VIEW, "view"),
86   LogClassMapping(SG_COCKPIT, "cockpit"),
87   LogClassMapping(SG_GENERAL, "general"),
88   LogClassMapping(SG_MATH, "math"),
89   LogClassMapping(SG_EVENT, "event"),
90   LogClassMapping(SG_AIRCRAFT, "aircraft"),
91   LogClassMapping(SG_AUTOPILOT, "autopilot"),
92   LogClassMapping(SG_IO, "io"),
93   LogClassMapping(SG_CLIPPER, "clipper"),
94   LogClassMapping(SG_NETWORK, "network"),
95   LogClassMapping(SG_UNDEFD, "")
96 };
97
98
99 /**
100  * Get the logging classes.
101  */
102 static const char *
103 getLoggingClasses ()
104 {
105   sgDebugClass classes = logbuf::get_log_classes();
106   static string result = "";    // FIXME
107   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
108     if ((classes&log_class_mappings[i].c) > 0) {
109       if (!result.empty())
110         result += '|';
111       result += log_class_mappings[i].name;
112     }
113   }
114   return result.c_str();
115 }
116
117
118 static void
119 addLoggingClass (const string &name)
120 {
121   sgDebugClass classes = logbuf::get_log_classes();
122   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
123     if (name == log_class_mappings[i].name) {
124       logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
125       return;
126     }
127   }
128   SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
129 }
130
131
132 /**
133  * Set the logging classes.
134  */
135 static void
136 setLoggingClasses (const char * c)
137 {
138   string classes = c;
139   logbuf::set_log_classes(SG_NONE);
140
141   if (classes == "none") {
142     SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
143     return;
144   }
145
146   if (classes.empty() || classes == "all") { // default
147     logbuf::set_log_classes(SG_ALL);
148     SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
149            << getLoggingClasses());
150     return;
151   }
152
153   string rest = classes;
154   string name = "";
155   int sep = rest.find('|');
156   while (sep > 0) {
157     name = rest.substr(0, sep);
158     rest = rest.substr(sep+1);
159     addLoggingClass(name);
160     sep = rest.find('|');
161   }
162   addLoggingClass(rest);
163   SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
164          << getLoggingClasses());
165 }
166
167
168 /**
169  * Get the logging priority.
170  */
171 static const char *
172 getLoggingPriority ()
173 {
174   switch (logbuf::get_log_priority()) {
175   case SG_BULK:
176     return "bulk";
177   case SG_DEBUG:
178     return "debug";
179   case SG_INFO:
180     return "info";
181   case SG_WARN:
182     return "warn";
183   case SG_ALERT:
184     return "alert";
185   default:
186     SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
187            << logbuf::get_log_priority());
188     return "unknown";
189   }
190 }
191
192
193 /**
194  * Set the logging priority.
195  */
196 static void
197 setLoggingPriority (const char * p)
198 {
199   string priority = p;
200   if (priority == "bulk") {
201     logbuf::set_log_priority(SG_BULK);
202   } else if (priority == "debug") {
203     logbuf::set_log_priority(SG_DEBUG);
204   } else if (priority.empty() || priority == "info") { // default
205     logbuf::set_log_priority(SG_INFO);
206   } else if (priority == "warn") {
207     logbuf::set_log_priority(SG_WARN);
208   } else if (priority == "alert") {
209     logbuf::set_log_priority(SG_ALERT);
210   } else {
211     SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
212   }
213   SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
214 }
215
216
217 /**
218  * Return the current frozen state.
219  */
220 static bool
221 getFreeze ()
222 {
223   return frozen;
224 }
225
226
227 /**
228  * Set the current frozen state.
229  */
230 static void
231 setFreeze (bool f)
232 {
233     frozen = f;
234
235     // Stop sound on a pause
236     SGSoundMgr *s = globals->get_soundmgr();
237     if ( s != NULL ) {
238         if ( f ) {
239             s->pause();
240         } else {
241             s->resume();
242         }
243     }
244 }
245
246
247 /**
248  * Return the current aircraft directory (UIUC) as a string.
249  */
250 static const char *
251 getAircraftDir ()
252 {
253   return aircraft_dir.c_str();
254 }
255
256
257 /**
258  * Set the current aircraft directory (UIUC).
259  */
260 static void
261 setAircraftDir (const char * dir)
262 {
263   aircraft_dir = dir;
264 }
265
266
267 /**
268  * Return the number of milliseconds elapsed since simulation started.
269  */
270 static double
271 getElapsedTime_sec ()
272 {
273   return globals->get_sim_time_sec();
274 }
275
276
277 /**
278  * Return the current Zulu time.
279  */
280 static const char *
281 getDateString ()
282 {
283   static char buf[64];          // FIXME
284   struct tm * t = globals->get_time_params()->getGmt();
285   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
286           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
287           t->tm_hour, t->tm_min, t->tm_sec);
288   return buf;
289 }
290
291
292 /**
293  * Set the current Zulu time.
294  */
295 static void
296 setDateString (const char * date_string)
297 {
298   static const SGPropertyNode *cur_time_override
299         = fgGetNode("/sim/time/cur-time-override", true);
300
301   SGTime * st = globals->get_time_params();
302   struct tm * current_time = st->getGmt();
303   struct tm new_time;
304
305                                 // Scan for basic ISO format
306                                 // YYYY-MM-DDTHH:MM:SS
307   int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
308                    &(new_time.tm_year), &(new_time.tm_mon),
309                    &(new_time.tm_mday), &(new_time.tm_hour),
310                    &(new_time.tm_min), &(new_time.tm_sec));
311
312                                 // Be pretty picky about this, so
313                                 // that strange things don't happen
314                                 // if the save file has been edited
315                                 // by hand.
316   if (ret != 6) {
317     SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
318            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
319     return;
320   }
321
322                                 // OK, it looks like we got six
323                                 // values, one way or another.
324   new_time.tm_year -= 1900;
325   new_time.tm_mon -= 1;
326
327                                 // Now, tell flight gear to use
328                                 // the new time.  This was far
329                                 // too difficult, by the way.
330   long int warp =
331     mktime(&new_time) - mktime(current_time) + globals->get_warp();
332   double lon = current_aircraft.fdm_state->get_Longitude();
333   double lat = current_aircraft.fdm_state->get_Latitude();
334   globals->set_warp(warp);
335   st->update(lon, lat, cur_time_override->getLongValue(), warp);
336 }
337
338 /**
339  * Return the GMT as a string.
340  */
341 static const char *
342 getGMTString ()
343 {
344   static char buf[16];          // FIXME
345   struct tm *t = globals->get_time_params()->getGmt();
346   sprintf(buf, " %.2d:%.2d:%.2d",
347           t->tm_hour, t->tm_min, t->tm_sec);
348   // cout << t << " " << buf << endl;
349   return buf;
350 }
351
352
353 /**
354  * Return the magnetic variation
355  */
356 static double
357 getMagVar ()
358 {
359   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
360 }
361
362
363 /**
364  * Return the magnetic dip
365  */
366 static double
367 getMagDip ()
368 {
369   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
370 }
371
372
373 /**
374  * Return the current heading in degrees.
375  */
376 static double
377 getHeadingMag ()
378 {
379   double magheading;
380   magheading = current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
381   if (magheading < 0) magheading += 360;
382   return magheading;
383 }
384
385
386 #ifdef FG_WEATHERCM
387
388 /**
389  * Get the current visibility (meters).
390  */
391 static double
392 getVisibility ()
393 {
394   return WeatherDatabase->getWeatherVisibility();
395 }
396
397
398 /**
399  * Set the current visibility (meters).
400  */
401 static void
402 setVisibility (double visibility)
403 {
404   WeatherDatabase->setWeatherVisibility(visibility);
405 }
406
407 /**
408  * Get the current wind north velocity (feet/second).
409  */
410 static double
411 getWindNorth ()
412 {
413   return current_aircraft.fdm_state->get_V_north_airmass();
414 }
415
416
417 /**
418  * Set the current wind north velocity (feet/second).
419  */
420 static void
421 setWindNorth (double speed)
422 {
423   current_aircraft.fdm_state
424     ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
425 }
426
427
428 /**
429  * Get the current wind east velocity (feet/second).
430  */
431 static double
432 getWindEast ()
433 {
434   return current_aircraft.fdm_state->get_V_east_airmass();
435 }
436
437
438 /**
439  * Set the current wind east velocity (feet/second).
440  */
441 static void
442 setWindEast (double speed)
443 {
444   SG_LOG(SG_GENERAL, SG_INFO,, "Set wind-east to " << speed );
445   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
446                                                            speed,
447                                                            getWindDown());
448 }
449
450
451 /**
452  * Get the current wind down velocity (feet/second).
453  */
454 static double
455 getWindDown ()
456 {
457   return current_aircraft.fdm_state->get_V_down_airmass();
458 }
459
460
461 /**
462  * Set the current wind down velocity (feet/second).
463  */
464 static void
465 setWindDown (double speed)
466 {
467   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
468                                                            getWindEast(),
469                                                            speed);
470 }
471
472 #endif // FG_WEATHERCM
473
474 static long
475 getWarp ()
476 {
477   return globals->get_warp();
478 }
479
480 static void
481 setWarp (long warp)
482 {
483   globals->set_warp(warp);
484 }
485
486 static long
487 getWarpDelta ()
488 {
489   return globals->get_warp_delta();
490 }
491
492 static void
493 setWarpDelta (long delta)
494 {
495   globals->set_warp_delta(delta);
496 }
497
498 static bool
499 getWindingCCW ()
500 {
501   return winding_ccw;
502 }
503
504 static void
505 setWindingCCW (bool state)
506 {
507   winding_ccw = state;
508   if ( winding_ccw )
509     glFrontFace ( GL_CCW );
510   else
511     glFrontFace ( GL_CW );
512 }
513
514 static bool
515 getFullScreen ()
516 {
517 #if defined(FX) && !defined(WIN32)
518   return globals->get_fullscreen();
519 #else
520   return false;
521 #endif
522 }
523
524 static void
525 setFullScreen (bool state)
526 {
527 #if defined(FX) && !defined(WIN32)
528   globals->set_fullscreen(state);
529 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
530   XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
531 #  endif
532 #endif
533 }
534
535 static bool
536 getFDMDataLogging ()
537 {
538   return fdm_data_logging;
539 }
540
541 static void
542 setFDMDataLogging (bool state)
543 {
544                                 // kludge; no getter or setter available
545   if (state != fdm_data_logging) {
546     fgToggleFDMdataLogging();
547     fdm_data_logging = state;
548   }
549 }
550
551 \f
552 ////////////////////////////////////////////////////////////////////////
553 // Tie the properties.
554 ////////////////////////////////////////////////////////////////////////
555
556 void
557 fgInitProps ()
558 {
559   SG_LOG(SG_GENERAL, SG_DEBUG, "start of fgInitProps()" );
560                                 // Simulation
561   fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
562   fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
563   fgTie("/sim/freeze/master", getFreeze, setFreeze);
564   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
565
566   fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
567   fgTie("/sim/time/gmt", getDateString, setDateString);
568   fgSetArchivable("/sim/time/gmt");
569   fgTie("/sim/time/gmt-string", getGMTString);
570
571                                 // Orientation
572   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
573
574                                 // Environment
575 #ifdef FG_WEATHERCM
576   fgTie("/environment/visibility-m", getVisibility, setVisibility);
577   fgSetArchivable("/environment/visibility-m");
578   fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
579   fgSetArchivable("/environment/wind-from-north-fps");
580   fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
581   fgSetArchivable("/environment/wind-from-east-fps");
582   fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
583   fgSetArchivable("/environment/wind-from-down-fps");
584 #endif
585
586   fgTie("/environment/magnetic-variation-deg", getMagVar);
587   fgTie("/environment/magnetic-dip-deg", getMagDip);
588
589   fgTie("/sim/time/warp", getWarp, setWarp, false);
590   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
591
592                                 // Misc. Temporary junk.
593   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
594   fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
595   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
596
597   SG_LOG(SG_GENERAL, SG_DEBUG, "end of fgInitProps()" );
598 }
599
600
601 void
602 fgUpdateProps ()
603 {
604 }
605
606
607 \f
608 ////////////////////////////////////////////////////////////////////////
609 // Save and restore.
610 ////////////////////////////////////////////////////////////////////////
611
612
613 /**
614  * Save the current state of the simulator to a stream.
615  */
616 bool
617 fgSaveFlight (ostream &output, bool write_all)
618 {
619
620   fgSetBool("/sim/presets/onground", false);
621   fgSetArchivable("/sim/presets/onground");
622   fgSetBool("/sim/presets/trim", false);
623   fgSetArchivable("/sim/presets/trim");
624   fgSetString("/sim/presets/speed-set", "UVW");
625   fgSetArchivable("/sim/presets/speed-set");
626
627   try {
628     writeProperties(output, globals->get_props(), write_all);
629   } catch (const sg_exception &e) {
630     guiErrorMessage("Error saving flight: ", e);
631     return false;
632   }
633   return true;
634 }
635
636
637 /**
638  * Restore the current state of the simulator from a stream.
639  */
640 bool
641 fgLoadFlight (istream &input)
642 {
643   SGPropertyNode props;
644   try {
645     readProperties(input, &props);
646   } catch (const sg_exception &e) {
647     guiErrorMessage("Error reading saved flight: ", e);
648     return false;
649   }
650
651   fgSetBool("/sim/presets/onground", false);
652   fgSetBool("/sim/presets/trim", false);
653   fgSetString("/sim/presets/speed-set", "UVW");
654
655   copyProperties(&props, globals->get_props());
656   // When loading a flight, make it the
657   // new initial state.
658   globals->saveInitialState();
659   return true;
660 }
661
662
663 bool
664 fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root)
665 {
666     string fullpath;
667     if (in_fg_root) {
668         SGPath loadpath(globals->get_fg_root());
669         loadpath.append(path);
670         fullpath = loadpath.str();
671     } else {
672         fullpath = path;
673     }
674
675     try {
676         readProperties(fullpath, props);
677     } catch (const sg_exception &e) {
678         guiErrorMessage("Error reading properties: ", e);
679         return false;
680     }
681     return true;
682 }
683
684
685 \f
686 ////////////////////////////////////////////////////////////////////////
687 // Property convenience functions.
688 ////////////////////////////////////////////////////////////////////////
689
690 SGPropertyNode *
691 fgGetNode (const char * path, bool create)
692 {
693   return globals->get_props()->getNode(path, create);
694 }
695
696 SGPropertyNode * 
697 fgGetNode (const char * path, int index, bool create)
698 {
699   return globals->get_props()->getNode(path, index, create);
700 }
701
702 bool
703 fgHasNode (const char * path)
704 {
705   return (fgGetNode(path, false) != 0);
706 }
707
708 void
709 fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
710 {
711   fgGetNode(path, true)->addChangeListener(listener);
712 }
713
714 void
715 fgAddChangeListener (SGPropertyChangeListener * listener,
716                      const char * path, int index)
717 {
718   fgGetNode(path, index, true)->addChangeListener(listener);
719 }
720
721 bool
722 fgGetBool (const char * name, bool defaultValue)
723 {
724   return globals->get_props()->getBoolValue(name, defaultValue);
725 }
726
727 int
728 fgGetInt (const char * name, int defaultValue)
729 {
730   return globals->get_props()->getIntValue(name, defaultValue);
731 }
732
733 int
734 fgGetLong (const char * name, long defaultValue)
735 {
736   return globals->get_props()->getLongValue(name, defaultValue);
737 }
738
739 float
740 fgGetFloat (const char * name, float defaultValue)
741 {
742   return globals->get_props()->getFloatValue(name, defaultValue);
743 }
744
745 double
746 fgGetDouble (const char * name, double defaultValue)
747 {
748   return globals->get_props()->getDoubleValue(name, defaultValue);
749 }
750
751 const char *
752 fgGetString (const char * name, const char * defaultValue)
753 {
754   return globals->get_props()->getStringValue(name, defaultValue);
755 }
756
757 bool
758 fgSetBool (const char * name, bool val)
759 {
760   return globals->get_props()->setBoolValue(name, val);
761 }
762
763 bool
764 fgSetInt (const char * name, int val)
765 {
766   return globals->get_props()->setIntValue(name, val);
767 }
768
769 bool
770 fgSetLong (const char * name, long val)
771 {
772   return globals->get_props()->setLongValue(name, val);
773 }
774
775 bool
776 fgSetFloat (const char * name, float val)
777 {
778   return globals->get_props()->setFloatValue(name, val);
779 }
780
781 bool
782 fgSetDouble (const char * name, double val)
783 {
784   return globals->get_props()->setDoubleValue(name, val);
785 }
786
787 bool
788 fgSetString (const char * name, const char * val)
789 {
790   return globals->get_props()->setStringValue(name, val);
791 }
792
793 void
794 fgSetArchivable (const char * name, bool state)
795 {
796   SGPropertyNode * node = globals->get_props()->getNode(name);
797   if (node == 0)
798     SG_LOG(SG_GENERAL, SG_ALERT,
799            "Attempt to set archive flag for non-existant property "
800            << name);
801   else
802     node->setAttribute(SGPropertyNode::ARCHIVE, state);
803 }
804
805 void
806 fgSetReadable (const char * name, bool state)
807 {
808   SGPropertyNode * node = globals->get_props()->getNode(name);
809   if (node == 0)
810     SG_LOG(SG_GENERAL, SG_ALERT,
811            "Attempt to set read flag for non-existant property "
812            << name);
813   else
814     node->setAttribute(SGPropertyNode::READ, state);
815 }
816
817 void
818 fgSetWritable (const char * name, bool state)
819 {
820   SGPropertyNode * node = globals->get_props()->getNode(name);
821   if (node == 0)
822     SG_LOG(SG_GENERAL, SG_ALERT,
823            "Attempt to set write flag for non-existant property "
824            << name);
825   else
826     node->setAttribute(SGPropertyNode::WRITE, state);
827 }
828
829 void
830 fgUntie (const char * name)
831 {
832   if (!globals->get_props()->untie(name))
833     SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
834 }
835
836
837 // end of fg_props.cxx