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