]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/fg_props.cxx
Update for changed SGPath::realpath signature
[flightgear.git] / src / Main / fg_props.cxx
index a68e2403ece39b64cc1d572582fe53fc98db5dc3..975a8a48cfe5dc4fa7923bdd1e2d795d45b955bc 100644 (file)
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 // $Id$
 
 #ifdef HAVE_CONFIG_H
-#  include <simgear/compiler.h>
+#  include "config.h"
 #endif
 
-#include <simgear/misc/exception.hxx>
-#include <simgear/magvar/magvar.hxx>
+#include <simgear/compiler.h>
+#include <simgear/structure/exception.hxx>
+#include <simgear/props/props_io.hxx>
+
 #include <simgear/timing/sg_time.hxx>
 #include <simgear/misc/sg_path.hxx>
-#include <simgear/sound/soundmgr.hxx>
-
-#include STL_IOSTREAM
-
-#include <ATC/ATCdisplay.hxx>
-#include <Aircraft/aircraft.hxx>
-#include <Time/tmp.hxx>
-#include <FDM/UIUCModel/uiuc_aircraftdir.h>
-#ifdef FG_WEATHERCM
-#  include <WeatherCM/FGLocalWeatherDatabase.h>
-#else
-#  include <Environment/environment.hxx>
-#endif // FG_WEATHERCM
-#include <Objects/matlib.hxx>
+#include <simgear/scene/model/particles.hxx>
+#include <simgear/sound/soundmgr_openal.hxx>
 
 #include <GUI/gui.h>
 
 #include "globals.hxx"
-#include "fgfs.hxx"
 #include "fg_props.hxx"
 
-SG_USING_STD(istream);
-SG_USING_STD(ostream);
-
-#ifdef FG_WEATHERCM
-static double getWindNorth ();
-static double getWindEast ();
-static double getWindDown ();
-#endif // FG_WEATHERCM
-
-static bool winding_ccw = true; // FIXME: temporary
-
-static bool fdm_data_logging = false; // FIXME: temporary
-
 static bool frozen = false;    // FIXME: temporary
 
-
-\f
+using std::string;
 ////////////////////////////////////////////////////////////////////////
 // Default property bindings (not yet handled by any module).
 ////////////////////////////////////////////////////////////////////////
@@ -93,6 +68,16 @@ LogClassMapping log_class_mappings [] = {
   LogClassMapping(SG_IO, "io"),
   LogClassMapping(SG_CLIPPER, "clipper"),
   LogClassMapping(SG_NETWORK, "network"),
+  LogClassMapping(SG_INSTR, "instrumentation"),
+  LogClassMapping(SG_ATC, "atc"),
+  LogClassMapping(SG_NASAL, "nasal"),
+  LogClassMapping(SG_SYSTEMS, "systems"),
+  LogClassMapping(SG_AI, "ai"),
+  LogClassMapping(SG_ENVIRONMENT, "environment"),
+  LogClassMapping(SG_SOUND, "sound"),
+  LogClassMapping(SG_NAVAID, "navaid"),
+  LogClassMapping(SG_GUI, "gui"),
+  LogClassMapping(SG_TERRASYNC, "terrasync"),
   LogClassMapping(SG_UNDEFD, "")
 };
 
@@ -100,44 +85,51 @@ LogClassMapping log_class_mappings [] = {
 /**
  * Get the logging classes.
  */
+// XXX Making the result buffer be global is a band-aid that hopefully
+// delays its destruction 'til after its last use.
+namespace
+{
+string loggingResult;
+}
+
 static const char *
 getLoggingClasses ()
 {
-  sgDebugClass classes = logbuf::get_log_classes();
-  static string result = "";   // FIXME
+  sgDebugClass classes = sglog().get_log_classes();
+  loggingResult.clear();
   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
     if ((classes&log_class_mappings[i].c) > 0) {
-      if (!result.empty())
-       result += '|';
-      result += log_class_mappings[i].name;
+      if (!loggingResult.empty())
+       loggingResult += '|';
+      loggingResult += log_class_mappings[i].name;
     }
   }
-  return result.c_str();
+  return loggingResult.c_str();
 }
 
 
 static void
 addLoggingClass (const string &name)
 {
-  sgDebugClass classes = logbuf::get_log_classes();
+  sgDebugClass classes = sglog().get_log_classes();
   for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
     if (name == log_class_mappings[i].name) {
-      logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
+      sglog().set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
       return;
     }
   }
-  SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
+  SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging class: " << name);
 }
 
 
 /**
  * Set the logging classes.
  */
-static void
+void
 setLoggingClasses (const char * c)
 {
   string classes = c;
-  logbuf::set_log_classes(SG_NONE);
+  sglog().set_log_classes(SG_NONE);
 
   if (classes == "none") {
     SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
@@ -145,7 +137,7 @@ setLoggingClasses (const char * c)
   }
 
   if (classes.empty() || classes == "all") { // default
-    logbuf::set_log_classes(SG_ALL);
+    sglog().set_log_classes(SG_ALL);
     SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
           << getLoggingClasses());
     return;
@@ -153,12 +145,16 @@ setLoggingClasses (const char * c)
 
   string rest = classes;
   string name = "";
-  int sep = rest.find('|');
-  while (sep > 0) {
+  string::size_type sep = rest.find('|');
+  if (sep == string::npos)
+    sep = rest.find(',');
+  while (sep != string::npos) {
     name = rest.substr(0, sep);
     rest = rest.substr(sep+1);
     addLoggingClass(name);
     sep = rest.find('|');
+    if (sep == string::npos)
+      sep = rest.find(',');
   }
   addLoggingClass(rest);
   SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
@@ -172,7 +168,7 @@ setLoggingClasses (const char * c)
 static const char *
 getLoggingPriority ()
 {
-  switch (logbuf::get_log_priority()) {
+  switch (sglog().get_log_priority()) {
   case SG_BULK:
     return "bulk";
   case SG_DEBUG:
@@ -185,7 +181,7 @@ getLoggingPriority ()
     return "alert";
   default:
     SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
-          << logbuf::get_log_priority());
+          << sglog().get_log_priority());
     return "unknown";
   }
 }
@@ -194,24 +190,26 @@ getLoggingPriority ()
 /**
  * Set the logging priority.
  */
-static void
+void
 setLoggingPriority (const char * p)
 {
+  if (p == 0)
+      return;
   string priority = p;
   if (priority == "bulk") {
-    logbuf::set_log_priority(SG_BULK);
+    sglog().set_log_priority(SG_BULK);
   } else if (priority == "debug") {
-    logbuf::set_log_priority(SG_DEBUG);
+    sglog().set_log_priority(SG_DEBUG);
   } else if (priority.empty() || priority == "info") { // default
-    logbuf::set_log_priority(SG_INFO);
+    sglog().set_log_priority(SG_INFO);
   } else if (priority == "warn") {
-    logbuf::set_log_priority(SG_WARN);
+    sglog().set_log_priority(SG_WARN);
   } else if (priority == "alert") {
-    logbuf::set_log_priority(SG_ALERT);
+    sglog().set_log_priority(SG_ALERT);
   } else {
     SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
   }
-  SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
+  SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << getLoggingPriority());
 }
 
 
@@ -234,34 +232,17 @@ setFreeze (bool f)
     frozen = f;
 
     // Stop sound on a pause
-    SoundMgr *s = globals->get_soundmgr();
-    if ( s != NULL ) {
+    SGSoundMgr *smgr = globals->get_subsystem<SGSoundMgr>();
+    if ( smgr != NULL ) {
         if ( f ) {
-            s->pause();
-        } else {
-            s->resume();
+            smgr->suspend();
+        } else if (fgGetBool("/sim/sound/working")) {
+            smgr->resume();
         }
     }
-}
-
-
-/**
- * Return the current aircraft directory (UIUC) as a string.
- */
-static const char *
-getAircraftDir ()
-{
-  return aircraft_dir.c_str();
-}
-
 
-/**
- * Set the current aircraft directory (UIUC).
- */
-static void
-setAircraftDir (const char * dir)
-{
-  aircraft_dir = dir;
+    // Pause the particle system
+    simgear::Particles::setFrozen(f);
 }
 
 
@@ -282,7 +263,14 @@ static const char *
 getDateString ()
 {
   static char buf[64];         // FIXME
-  struct tm * t = globals->get_time_params()->getGmt();
+  
+  SGTime * st = globals->get_time_params();
+  if (!st) {
+    buf[0] = 0;
+    return buf;
+  }
+  
+  struct tm * t = st->getGmt();
   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
          t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
          t->tm_hour, t->tm_min, t->tm_sec);
@@ -296,9 +284,6 @@ getDateString ()
 static void
 setDateString (const char * date_string)
 {
-  static const SGPropertyNode *cur_time_override
-       = fgGetNode("/sim/time/cur-time-override", true);
-
   SGTime * st = globals->get_time_params();
   struct tm * current_time = st->getGmt();
   struct tm new_time;
@@ -315,7 +300,7 @@ setDateString (const char * date_string)
                                // if the save file has been edited
                                // by hand.
   if (ret != 6) {
-    SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
+    SG_LOG(SG_INPUT, SG_WARN, "Date/time string " << date_string
           << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
     return;
   }
@@ -324,17 +309,13 @@ setDateString (const char * date_string)
                                // values, one way or another.
   new_time.tm_year -= 1900;
   new_time.tm_mon -= 1;
-
                                // Now, tell flight gear to use
                                // the new time.  This was far
                                // too difficult, by the way.
   long int warp =
     mktime(&new_time) - mktime(current_time) + globals->get_warp();
-  double lon = current_aircraft.fdm_state->get_Longitude();
-  double lat = current_aircraft.fdm_state->get_Latitude();
-  globals->set_warp(warp);
-  st->update(lon, lat, cur_time_override->getLongValue(), warp);
-  fgUpdateSkyAndLightingParams();
+    
+  fgSetInt("/sim/time/warp", warp);
 }
 
 /**
@@ -343,287 +324,308 @@ setDateString (const char * date_string)
 static const char *
 getGMTString ()
 {
-  static char buf[16];         // FIXME
-  struct tm *t = globals->get_time_params()->getGmt();
-  sprintf(buf, " %.2d:%.2d:%.2d",
-         t->tm_hour, t->tm_min, t->tm_sec);
-  // cout << t << " " << buf << endl;
+  static char buf[16];
+  SGTime * st = globals->get_time_params();
+  if (!st) {
+    buf[0] = 0;
+    return buf;
+  }
+  
+  struct tm *t = st->getGmt();
+  snprintf(buf, 16, "%.2d:%.2d:%.2d",
+      t->tm_hour, t->tm_min, t->tm_sec);
   return buf;
 }
 
-
-/**
- * Get the texture rendering state.
- */
-static bool
-getTextures ()
-{
-  return (material_lib.get_step() == 0);
-}
-
-
-/**
- * Set the texture rendering state.
- */
-static void
-setTextures (bool textures)
-{
-  if (textures)
-    material_lib.set_step(0);
-  else
-    material_lib.set_step(1);
-}
-
-
-/**
- * Return the magnetic variation
- */
-static double
-getMagVar ()
-{
-  return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
-}
-
-
-/**
- * Return the magnetic dip
- */
-static double
-getMagDip ()
-{
-  return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
-}
-
-
 /**
  * Return the current heading in degrees.
  */
 static double
 getHeadingMag ()
 {
-  return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
+  double magheading = fgGetDouble("/orientation/heading-deg") -
+    fgGetDouble("/environment/magnetic-variation-deg");
+  return SGMiscd::normalizePeriodic(0, 360, magheading );
 }
 
-
-#ifdef FG_WEATHERCM
-
 /**
- * Get the current visibility (meters).
+ * Return the current track in degrees.
  */
 static double
-getVisibility ()
+getTrackMag ()
 {
-  return WeatherDatabase->getWeatherVisibility();
-}
-
-
-/**
- * Set the current visibility (meters).
- */
-static void
-setVisibility (double visibility)
-{
-  WeatherDatabase->setWeatherVisibility(visibility);
-}
-
-/**
- * Get the current wind north velocity (feet/second).
- */
-static double
-getWindNorth ()
-{
-  return current_aircraft.fdm_state->get_V_north_airmass();
+  double magtrack = fgGetDouble("/orientation/track-deg") -
+    fgGetDouble("/environment/magnetic-variation-deg");
+  return SGMiscd::normalizePeriodic(0, 360, magtrack );
 }
 
+////////////////////////////////////////////////////////////////////////
+// Tie the properties.
+////////////////////////////////////////////////////////////////////////
+SGConstPropertyNode_ptr FGProperties::_longDeg;
+SGConstPropertyNode_ptr FGProperties::_latDeg;
+SGConstPropertyNode_ptr FGProperties::_lonLatformat;
 
-/**
- * Set the current wind north velocity (feet/second).
+/*
+ * Format the latitude and longitude floats into a character array using a variety of coordinate formats.
  */
 static void
-setWindNorth (double speed)
-{
-  current_aircraft.fdm_state
-    ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
-}
-
-
-/**
- * Get the current wind east velocity (feet/second).
- */
-static double
-getWindEast ()
-{
-  return current_aircraft.fdm_state->get_V_east_airmass();
-}
+formatLatLongString (double deg, int format, char *buf, char c) {
+  double min, sec;
+  int sign = deg < 0.0 ? -1 : 1;
+  deg = fabs(deg);
+
+  if (format == 0) {
+    // d.dddddd' (DDD format).
+    snprintf(buf, 32, "%3.6f%c", deg, c);
+
+  } else if (format == 1) {
+    // d mm.mmm' (DMM format) -- uses a round-off factor tailored to the
+    // required precision of the minutes field (three decimal places),
+    // preventing minute values of 60.
+    min = (deg - int(deg)) * 60.0;
+    if (min >= 59.9995) {
+        min -= 60.0;
+        deg += 1.0;
+    }
+    snprintf(buf, 32, "%d*%06.3f'%c", int(deg), fabs(min), c);
+
+  } else if (format == 2) {
+    // d mm'ss.s" (DMS format) -- uses a round-off factor tailored to the
+    // required precision of the seconds field (one decimal place),
+    // preventing second values of 60.
+    min = (deg - int(deg)) * 60.0;
+    sec = (min - int(min)) * 60.0;
+    if (sec >= 59.95) {
+        sec -= 60.0;
+        min += 1.0;
+        if (min >= 60.0) {
+            min -= 60.0;
+            deg += 1.0;
+        }
+    }
+    snprintf(buf, 32, "%d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c);
+
+  } else if (format == 3) {
+    // d.dddddd' (signed DDD format).
+    snprintf(buf, 32, "%3.6f", sign*deg);
+
+  } else if (format == 4) {
+    // d mm.mmm' (signed DMM format).
+    min = (deg - int(deg)) * 60.0;
+    if (min >= 59.9995) {
+        min -= 60.0;
+        deg += 1.0;
+    }
+    if (sign == 1) {
+        snprintf(buf, 32, "%d*%06.3f'", int(deg), fabs(min));
+    } else {
+        snprintf(buf, 32, "-%d*%06.3f'", int(deg), fabs(min));
+    }
 
+  } else if (format == 5) {
+    // d mm'ss.s" (signed DMS format).
+    min = (deg - int(deg)) * 60.0;
+    sec = (min - int(min)) * 60.0;
+    if (sec >= 59.95) {
+        sec -= 60.0;
+        min += 1.0;
+        if (min >= 60.0) {
+            min -= 60.0;
+            deg += 1.0;
+        }
+    }
+    if (sign == 1) {
+        snprintf(buf, 32, "%d*%02d'%04.1f\"", int(deg), int(min), fabs(sec));
+    } else {
+        snprintf(buf, 32, "-%d*%02d'%04.1f\"", int(deg), int(min), fabs(sec));
+    }
 
-/**
- * Set the current wind east velocity (feet/second).
- */
-static void
-setWindEast (double speed)
-{
-  SG_LOG(SG_GENERAL, SG_INFO,, "Set wind-east to " << speed );
-  current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
-                                                          speed,
-                                                          getWindDown());
-}
+  } else if (format == 6) {
+    // dd.dddddd X, ddd.dddddd X (zero padded DDD format).
+    if (c == 'N' || c == 'S') {
+      snprintf(buf, 32, "%09.6f%c", deg, c);
+    } else {
+      snprintf(buf, 32, "%010.6f%c", deg, c);
+    }
 
+  } else if (format == 7) {
+    // dd mm.mmm' X, ddd mm.mmm' X (zero padded DMM format).
+    min = (deg - int(deg)) * 60.0;
+    if (min >= 59.9995) {
+        min -= 60.0;
+        deg += 1.0;
+    }
+    if (c == 'N' || c == 'S') {
+      snprintf(buf, 32, "%02d*%06.3f'%c", int(deg), fabs(min), c);
+    } else {
+      snprintf(buf, 32, "%03d*%06.3f'%c", int(deg), fabs(min), c);
+    }
 
-/**
- * Get the current wind down velocity (feet/second).
- */
-static double
-getWindDown ()
-{
-  return current_aircraft.fdm_state->get_V_down_airmass();
-}
+  } else if (format == 8) {
+    // dd mm'ss.s" X, dd mm'ss.s" X (zero padded DMS format).
+    min = (deg - int(deg)) * 60.0;
+    sec = (min - int(min)) * 60.0;
+    if (sec >= 59.95) {
+        sec -= 60.0;
+        min += 1.0;
+        if (min >= 60.0) {
+            min -= 60.0;
+            deg += 1.0;
+        }
+    }
+    if (c == 'N' || c == 'S') {
+      snprintf(buf, 32, "%02d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c);
+    } else {
+      snprintf(buf, 32, "%03d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c);
+    }
 
+  } else if (format == 9) {
+    // dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard).
+    min = (deg - int(deg)) * 60.0;
+    if (min >= 59.9995) {
+        min -= 60.0;
+        deg += 1.0;
+    }
+    if (c == 'N' || c == 'S') {
+        snprintf(buf, 32, "%02d* %02d'.%03d%c", int(deg), int(min), int(SGMisc<double>::round((min-int(min))*1000)), c);
+    } else {
+        snprintf(buf, 32, "%03d* %02d'.%03d%c", int(deg), int(min), int(SGMisc<double>::round((min-int(min))*1000)), c);
+    }
 
-/**
- * Set the current wind down velocity (feet/second).
- */
-static void
-setWindDown (double speed)
-{
-  current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
-                                                          getWindEast(),
-                                                          speed);
+  } else {
+    // Empty the buffer for all invalid formats.
+    buf[0] = '\0';
+  }
 }
 
-#endif // FG_WEATHERCM
-
-static long
-getWarp ()
+const char *
+FGProperties::getLongitudeString ()
 {
-  return globals->get_warp();
-}
+  static char buf[32];
+  double d = _longDeg->getDoubleValue();
+  int format = _lonLatformat->getIntValue();
 
-static void
-setWarp (long warp)
-{
-  globals->set_warp(warp);
+  char c = d < 0.0 ? 'W' : 'E';
+  formatLatLongString(d, format, buf, c);
+  return buf;
 }
 
-static long
-getWarpDelta ()
+const char *
+FGProperties::getLatitudeString ()
 {
-  return globals->get_warp_delta();
-}
+  static char buf[32];
+  double d = _latDeg->getDoubleValue();
+  int format = _lonLatformat->getIntValue();
 
-static void
-setWarpDelta (long delta)
-{
-  globals->set_warp_delta(delta);
+  char c = d < 0.0 ? 'S' : 'N';
+  formatLatLongString(d, format, buf, c);
+  return buf;
 }
 
-static bool
-getWindingCCW ()
-{
-  return winding_ccw;
-}
 
-static void
-setWindingCCW (bool state)
-{
-  winding_ccw = state;
-  if ( winding_ccw )
-    glFrontFace ( GL_CCW );
-  else
-    glFrontFace ( GL_CW );
-}
 
-static bool
-getFullScreen ()
-{
-#if defined(FX) && !defined(WIN32)
-  return globals->get_fullscreen();
-#else
-  return false;
-#endif
-}
+\f
 
-static void
-setFullScreen (bool state)
+FGProperties::FGProperties ()
 {
-#if defined(FX) && !defined(WIN32)
-  globals->set_fullscreen(state);
-#  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
-  XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
-#  endif
-#endif
 }
 
-static bool
-getFDMDataLogging ()
+FGProperties::~FGProperties ()
 {
-  return fdm_data_logging;
 }
 
-static void
-setFDMDataLogging (bool state)
+void
+FGProperties::init ()
 {
-                               // kludge; no getter or setter available
-  if (state != fdm_data_logging) {
-    fgToggleFDMdataLogging();
-    fdm_data_logging = state;
-  }
 }
 
-\f
-////////////////////////////////////////////////////////////////////////
-// Tie the properties.
-////////////////////////////////////////////////////////////////////////
-
 void
-fgInitProps ()
-{
-  SG_LOG(SG_GENERAL, SG_DEBUG, "start of fgInitProps()" );
-                               // Simulation
-  fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
-  fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
-  fgTie("/sim/freeze/master", getFreeze, setFreeze);
-  fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
-
-  fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
-  fgTie("/sim/time/gmt", getDateString, setDateString);
+FGProperties::bind ()
+{
+  _longDeg      = fgGetNode("/position/longitude-deg", true);
+  _latDeg       = fgGetNode("/position/latitude-deg", true);
+  _lonLatformat = fgGetNode("/sim/lon-lat-format", true);
+
+  _offset = fgGetNode("/sim/time/local-offset", true);
+
+  // utc date/time
+  _uyear = fgGetNode("/sim/time/utc/year", true);
+  _umonth = fgGetNode("/sim/time/utc/month", true);
+  _uday = fgGetNode("/sim/time/utc/day", true);
+  _uhour = fgGetNode("/sim/time/utc/hour", true);
+  _umin = fgGetNode("/sim/time/utc/minute", true);
+  _usec = fgGetNode("/sim/time/utc/second", true);
+  _uwday = fgGetNode("/sim/time/utc/weekday", true);
+  _udsec = fgGetNode("/sim/time/utc/day-seconds", true);
+
+  // real local date/time
+  _ryear = fgGetNode("/sim/time/real/year", true);
+  _rmonth = fgGetNode("/sim/time/real/month", true);
+  _rday = fgGetNode("/sim/time/real/day", true);
+  _rhour = fgGetNode("/sim/time/real/hour", true);
+  _rmin = fgGetNode("/sim/time/real/minute", true);
+  _rsec = fgGetNode("/sim/time/real/second", true);
+  _rwday = fgGetNode("/sim/time/real/weekday", true);
+
+  _tiedProperties.setRoot(globals->get_props());
+
+  // Simulation
+  _tiedProperties.Tie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
+  _tiedProperties.Tie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
+  _tiedProperties.Tie("/sim/freeze/master", getFreeze, setFreeze);
+
+  _tiedProperties.Tie<double>("/sim/time/elapsed-sec", getElapsedTime_sec);
+  _tiedProperties.Tie("/sim/time/gmt", getDateString, setDateString);
   fgSetArchivable("/sim/time/gmt");
-  fgTie("/sim/time/gmt-string", getGMTString);
-  fgTie("/sim/rendering/textures", getTextures, setTextures);
-
-                               // Orientation
-  fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
-
-                               // Environment
-#ifdef FG_WEATHERCM
-  fgTie("/environment/visibility-m", getVisibility, setVisibility);
-  fgSetArchivable("/environment/visibility-m");
-  fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
-  fgSetArchivable("/environment/wind-from-north-fps");
-  fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
-  fgSetArchivable("/environment/wind-from-east-fps");
-  fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
-  fgSetArchivable("/environment/wind-from-down-fps");
-#endif
+  _tiedProperties.Tie<const char*>("/sim/time/gmt-string", getGMTString);
 
-  fgTie("/environment/magnetic-variation-deg", getMagVar);
-  fgTie("/environment/magnetic-dip-deg", getMagDip);
+  // Position
+  _tiedProperties.Tie<const char*>("/position/latitude-string", getLatitudeString);
+  _tiedProperties.Tie<const char*>("/position/longitude-string", getLongitudeString);
 
-  fgTie("/sim/time/warp", getWarp, setWarp, false);
-  fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
+  // Orientation
+  _tiedProperties.Tie<double>("/orientation/heading-magnetic-deg", getHeadingMag);
+  _tiedProperties.Tie<double>("/orientation/track-magnetic-deg", getTrackMag);
+}
 
-                               // Misc. Temporary junk.
-  fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
-  fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
-  fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
+void
+FGProperties::unbind ()
+{
+    _tiedProperties.Untie();
 
-  SG_LOG(SG_GENERAL, SG_DEBUG, "end of fgInitProps()" );
+    // drop static references to properties
+    _longDeg = 0;
+    _latDeg = 0;
+    _lonLatformat = 0;
 }
 
-
 void
-fgUpdateProps ()
-{
+FGProperties::update (double dt)
+{
+    _offset->setIntValue(globals->get_time_params()->get_local_offset());
+
+    // utc date/time
+    struct tm *u = globals->get_time_params()->getGmt();
+    _uyear->setIntValue(u->tm_year + 1900);
+    _umonth->setIntValue(u->tm_mon + 1);
+    _uday->setIntValue(u->tm_mday);
+    _uhour->setIntValue(u->tm_hour);
+    _umin->setIntValue(u->tm_min);
+    _usec->setIntValue(u->tm_sec);
+    _uwday->setIntValue(u->tm_wday);
+    _udsec->setIntValue(u->tm_hour * 3600 + u->tm_min * 60 + u->tm_sec);
+
+    // real local date/time
+    time_t real = time(0);
+    struct tm *r = localtime(&real);
+    _ryear->setIntValue(r->tm_year + 1900);
+    _rmonth->setIntValue(r->tm_mon + 1);
+    _rday->setIntValue(r->tm_mday);
+    _rhour->setIntValue(r->tm_hour);
+    _rmin->setIntValue(r->tm_min);
+    _rsec->setIntValue(r->tm_sec);
+    _rwday->setIntValue(r->tm_wday);
 }
 
 
@@ -637,7 +639,7 @@ fgUpdateProps ()
  * Save the current state of the simulator to a stream.
  */
 bool
-fgSaveFlight (ostream &output, bool write_all)
+fgSaveFlight (std::ostream &output, bool write_all)
 {
 
   fgSetBool("/sim/presets/onground", false);
@@ -661,7 +663,7 @@ fgSaveFlight (ostream &output, bool write_all)
  * Restore the current state of the simulator from a stream.
  */
 bool
-fgLoadFlight (istream &input)
+fgLoadFlight (std::istream &input)
 {
   SGPropertyNode props;
   try {
@@ -676,27 +678,25 @@ fgLoadFlight (istream &input)
   fgSetString("/sim/presets/speed-set", "UVW");
 
   copyProperties(&props, globals->get_props());
-  // When loading a flight, make it the
-  // new initial state.
-  globals->saveInitialState();
+
   return true;
 }
 
 
 bool
-fgLoadProps (const char * path, SGPropertyNode * props, bool in_fg_root)
+fgLoadProps (const std::string& path, SGPropertyNode * props, bool in_fg_root, int default_mode)
 {
-    string fullpath;
+    SGPath fullpath;
     if (in_fg_root) {
         SGPath loadpath(globals->get_fg_root());
         loadpath.append(path);
-        fullpath = loadpath.str();
+        fullpath = loadpath;
     } else {
-        fullpath = path;
+        fullpath = SGPath::fromUtf8(path);
     }
 
     try {
-        readProperties(fullpath, props);
+        readProperties(fullpath, props, default_mode);
     } catch (const sg_exception &e) {
         guiErrorMessage("Error reading properties: ", e);
         return false;
@@ -753,7 +753,7 @@ fgGetInt (const char * name, int defaultValue)
   return globals->get_props()->getIntValue(name, defaultValue);
 }
 
-int
+long
 fgGetLong (const char * name, long defaultValue)
 {
   return globals->get_props()->getLongValue(name, defaultValue);
@@ -818,7 +818,7 @@ fgSetArchivable (const char * name, bool state)
 {
   SGPropertyNode * node = globals->get_props()->getNode(name);
   if (node == 0)
-    SG_LOG(SG_GENERAL, SG_ALERT,
+    SG_LOG(SG_GENERAL, SG_DEBUG,
           "Attempt to set archive flag for non-existant property "
           << name);
   else
@@ -830,7 +830,7 @@ fgSetReadable (const char * name, bool state)
 {
   SGPropertyNode * node = globals->get_props()->getNode(name);
   if (node == 0)
-    SG_LOG(SG_GENERAL, SG_ALERT,
+    SG_LOG(SG_GENERAL, SG_DEBUG,
           "Attempt to set read flag for non-existant property "
           << name);
   else
@@ -842,7 +842,7 @@ fgSetWritable (const char * name, bool state)
 {
   SGPropertyNode * node = globals->get_props()->getNode(name);
   if (node == 0)
-    SG_LOG(SG_GENERAL, SG_ALERT,
+    SG_LOG(SG_GENERAL, SG_DEBUG,
           "Attempt to set write flag for non-existant property "
           << name);
   else
@@ -850,10 +850,21 @@ fgSetWritable (const char * name, bool state)
 }
 
 void
-fgUntie (const char * name)
+fgUntie(const char * name)
 {
-  if (!globals->get_props()->untie(name))
+  SGPropertyNode* node = globals->get_props()->getNode(name);
+  if (!node) {
+    SG_LOG(SG_GENERAL, SG_WARN, "fgUntie: unknown property " << name);
+    return;
+  }
+  
+  if (!node->isTied()) {
+    return;
+  }
+  
+  if (!node->untie()) {
     SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
+  }
 }