]> git.mxchange.org Git - flightgear.git/blob - src/Main/save.cxx
Added a load/save state function contributed by David Megginson.
[flightgear.git] / src / Main / save.cxx
1 // save.cxx -- class to save and restore a flight.
2 //
3 // Written by Curtis Olson, started November 1999.
4 //
5 // Copyright (C) 1999  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
24 /*
25 CHANGES:
26 - time is now working
27 - autopilot is working (even with GPS)
28
29 TODO:
30 - use a separate options object so that we can roll back on error
31 - use proper FGFS logging
32 - add view direction, and other stuff
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #  include <config.h>
37 #endif
38
39 #include <iostream>
40
41 #include <Include/fg_types.hxx>
42 #include <Include/fg_constants.h>
43 #include <Aircraft/aircraft.hxx>
44 #include <Controls/controls.hxx>
45 #include <Autopilot/autopilot.hxx>
46 #include <Time/fg_time.hxx>
47 #ifndef FG_OLD_WEATHER
48 #  include <WeatherCM/FGLocalWeatherDatabase.h>
49 #else
50 #  include <Weather/weather.hxx>
51 #endif
52
53
54 #include "options.hxx"
55 #include "save.hxx"
56 #include "fg_init.hxx"
57
58 FG_USING_NAMESPACE(std);
59
60                                 // FIXME: these are not part of the
61                                 // published interface!!!
62 extern fgAPDataPtr APDataGlobal;
63 extern void fgAPAltitudeSet (double new_altitude);
64 extern void fgAPHeadingSet (double new_heading);
65
66 #define SAVE(name, value) { output << name << ": " << value << endl; }
67
68 /**
69  * Save the current state of the simulator to a stream.
70  */
71 bool
72 fgSaveFlight (ostream &output)
73 {
74   char tb[100];
75   const FGInterface * f = current_aircraft.fdm_state;
76   struct tm *t = FGTime::cur_time_params->getGmt();
77
78   output << "#!fgfs" << endl;
79
80   //
81   // Simulation
82   //
83   SAVE("flight-model", current_options.get_flight_model());
84   SAVE("time", mktime(t));
85   SAVE("hud", current_options.get_hud_status());
86   SAVE("panel", current_options.get_panel_status());
87
88   // 
89   // Location
90   //
91   SAVE("latitude", (f->get_Latitude() * RAD_TO_DEG));
92   SAVE("longitude", (f->get_Longitude() * RAD_TO_DEG));
93   SAVE("altitude", f->get_Altitude());
94
95   //
96   // Orientation
97   //
98   SAVE("heading", (f->get_Psi() * RAD_TO_DEG));
99   SAVE("pitch", (f->get_Theta() * RAD_TO_DEG));
100   SAVE("roll", (f->get_Phi() * RAD_TO_DEG));
101
102   //
103   // Velocities
104   //
105   SAVE("speed-north", f->get_V_north());
106   SAVE("speed-east", f->get_V_east());
107   SAVE("speed-down", f->get_V_down());
108
109   //
110   // Primary controls
111   //
112   SAVE("elevator", controls.get_elevator());
113   SAVE("aileron", controls.get_aileron());
114   SAVE("rudder", controls.get_rudder());
115                                 // FIXME: save each throttle separately
116   SAVE("throttle", controls.get_throttle(0));
117
118   //
119   // Secondary controls
120   //
121   SAVE("elevator-trim", controls.get_elevator_trim());
122   SAVE("flaps", controls.get_flaps());
123                                 // FIXME: save each brake separately
124   SAVE("brake", controls.get_brake(0));
125
126   //
127   // Navigation.
128   //
129   if (current_options.get_airport_id().length() > 0) {
130     SAVE("target-airport", current_options.get_airport_id());
131   }
132   SAVE("autopilot-altitude-lock", fgAPAltitudeEnabled());
133   SAVE("autopilot-altitude", fgAPget_TargetAltitude() * METER_TO_FEET);
134   SAVE("autopilot-heading-lock", fgAPHeadingEnabled());
135   SAVE("autopilot-heading", fgAPget_TargetHeading());
136   SAVE("autopilot-gps-lock", fgAPWayPointEnabled());
137   SAVE("autopilot-gps-lat", fgAPget_TargetLatitude());
138   SAVE("autopilot-gps-lon", fgAPget_TargetLongitude());
139
140   //
141   // Environment.
142   //
143 #ifndef FG_OLD_WEATHER
144   SAVE("visibility", WeatherDatabase->getWeatherVisibility());
145 #else
146   SAVE("visibility", current_weather.get_visibility());
147 #endif
148
149   return true;
150 }
151
152
153 /**
154  * Restore the current state of the simulator from a stream.
155  */
156 bool
157 fgLoadFlight (istream &input)
158 {
159   FGInterface * f = current_aircraft.fdm_state;
160   string text;
161   double n;
162   long int i;
163
164   double elevator = controls.get_elevator();
165   double aileron = controls.get_aileron();
166   double rudder = controls.get_rudder();
167   double throttle = controls.get_throttle(0);
168   double elevator_trim = controls.get_elevator_trim();
169   double flaps = controls.get_flaps();
170   double brake =  controls.get_brake(FGControls::ALL_WHEELS);
171
172   bool ap_heading_lock = false;
173   double ap_heading = 0;
174   bool ap_altitude_lock = false;
175   double ap_altitude = 0;
176   bool ap_gps_lock = false;
177   double ap_gps_lat = 0;
178   double ap_gps_lon = 0;
179
180   string airport_id = current_options.get_airport_id();
181   current_options.set_airport_id("");
182   current_options.set_time_offset(0);
183   current_options.set_time_offset_type(fgOPTIONS::FG_TIME_GMT_OFFSET);
184
185   if (!input.good() || input.eof()) {
186     cout << "Stream is no good!\n";
187     return false;
188   }
189
190   input >> text;
191   if (text != "#!fgfs") {
192     printf("Bad save file format!\n");
193     return false;
194   }
195
196
197   while (input.good() && !input.eof()) {
198     input >> text;
199
200     //
201     // Simulation.
202     //
203
204     if (text == "flight-model:") {
205       input >> i;
206       cout << "flight model is " << i << endl;
207       current_options.set_flight_model(i);
208     }
209
210     else if (text == "time:") {
211       input >> i;
212       cout << "saved time is " << i << endl;
213       current_options.set_time_offset(i);
214       current_options.set_time_offset_type(fgOPTIONS::FG_TIME_GMT_ABSOLUTE);
215       FGTime::cur_time_params->init(*cur_fdm_state);
216       FGTime::cur_time_params->update(*cur_fdm_state);
217     }
218
219     else if (text == "hud:") {
220       input >> i;
221       cout << "hud status is " << i << endl;
222       current_options.set_hud_status(i);
223     }
224
225     else if (text == "panel:") {
226       input >> i;
227       cout << "panel status is " << i << endl;
228       if (current_options.get_panel_status() != i) {
229         current_options.toggle_panel();
230       }
231     }
232
233     //
234     // Location
235     //
236       
237     else if (text == "latitude:") {
238       input >> n;
239       cout << "latitude is " << n << endl;
240       current_options.set_lat(n);
241     } else if (text == "longitude:") {
242       input >> n;
243       cout << "longitude is " << n << endl;
244       current_options.set_lon(n);
245     } else if (text == "altitude:") {
246       input >> n;
247       cout << "altitude is " << n << endl;
248       current_options.set_altitude(n * FEET_TO_METER);
249     } 
250
251     //
252     // Orientation
253     //
254
255     else if (text == "heading:") {
256       input >> n;
257       cout << "heading is " << n << endl;
258       current_options.set_heading(n);
259     } else if (text == "pitch:") {
260       input >> n;
261       cout << "pitch is " << n << endl;
262       current_options.set_pitch(n);
263     } else if (text == "roll:") {
264       input >> n;
265       cout << "roll is " << n << endl;
266       current_options.set_roll(n);
267     } 
268
269     //
270     // Velocities
271     //
272
273     else if (text == "speed-north:") {
274       input >> n;
275       cout << "speed north is " << n << endl;
276       current_options.set_uBody(n);
277     } else if (text == "speed-east:") {
278       input >> n;
279       cout << "speed east is " << n << endl;
280       current_options.set_vBody(n);
281     } else if (text == "speed-down:") {
282       input >> n;
283       cout << "speed down is " << n << endl;
284       current_options.set_wBody(n);
285     } 
286
287     //
288     // Primary controls
289     //
290
291     else if (text == "elevator:") {
292       input >> elevator;
293       cout << "elevator is " << elevator << endl;
294     }
295
296     else if (text == "aileron:") {
297       input >> aileron;
298       cout << "aileron is " << aileron << endl;
299     }
300
301     else if (text == "rudder:") {
302       input >> rudder;
303       cout << "rudder is " << rudder << endl;
304     }
305
306                                 // FIXME: assumes single engine
307     else if (text == "throttle:") {
308       input >> throttle;
309       cout << "throttle is " << throttle << endl;
310     }
311
312     //
313     // Secondary controls
314
315     else if (text == "elevator-trim:") {
316       input >> elevator_trim;
317       cout << "elevator trim is " << elevator_trim << endl;
318     }
319
320     else if (text == "flaps:") {
321       input >> flaps;
322       cout << "flaps are " << flaps << endl;
323     }
324
325     else if (text == "brake:") {
326       input >> brake;
327       cout << "brake is " << brake << endl;
328     }
329
330     //
331     // Navigation.
332     //
333
334     else if (text == "target-airport:") {
335       input >> airport_id;
336       cout << "target airport is " << airport_id << endl;
337     }
338
339     else if (text == "autopilot-altitude-lock:") {
340       input >> ap_altitude_lock;
341       cout << "autopilot altitude lock is " << ap_altitude_lock << endl;
342     }
343
344     else if (text == "autopilot-altitude:") {
345       input >> ap_altitude;
346       cout << "autopilot altitude is " << ap_altitude << endl;
347     }
348
349     else if (text == "autopilot-heading-lock:") {
350       input >> ap_heading_lock;
351       cout << "autopilot heading lock is " << ap_heading_lock << endl;
352     }
353
354     else if (text == "autopilot-heading:") {
355       input >> ap_heading;
356       cout << "autopilot heading is " << ap_heading << endl;
357     }
358
359     else if (text == "autopilot-gps-lock:") {
360       input >> ap_gps_lock;
361       cout << "autopilot GPS lock is " << ap_gps_lock << endl;
362     }
363
364     else if (text == "autopilot-gps-lat:") {
365       input >> ap_gps_lat;
366     }
367
368     else if (text == "autopilot-gps-lon:") {
369       input >> ap_gps_lon;
370     }
371
372     //
373     // Environment.
374     //
375
376     else if (text == "visibility:") {
377       input >> n;
378       cout << "visibility is " << n << endl;
379       
380 #ifndef FG_OLD_WEATHER
381       WeatherDatabase->setWeatherVisibility(n);
382 #else
383       current_weather.set_visibility(n);
384 #endif
385     }
386
387     //
388     // Don't die if we don't recognize something
389     //
390     
391     else {
392       cerr << "Skipping unknown field: " << text << endl;
393       input >> text;
394     }
395   }
396
397   fgReInitSubsystems();
398
399                                 // Set airport and controls after the
400                                 // re-init.
401   current_options.set_airport_id(airport_id);
402
403                                 // The controls have to be set after
404                                 // the reinit
405   controls.set_elevator(elevator);
406   controls.set_aileron(aileron);
407   controls.set_rudder(rudder);
408   controls.set_throttle(FGControls::ALL_ENGINES, throttle);
409   controls.set_elevator_trim(elevator_trim);
410   controls.set_flaps(flaps);
411   controls.set_brake(FGControls::ALL_WHEELS, brake);
412
413                                 // Ditto for the autopilot.
414                                 // FIXME: shouldn't have to use
415                                 // APDataGlobal.
416   APDataGlobal->heading_hold = ap_heading_lock;
417   APDataGlobal->altitude_hold = ap_altitude_lock;
418   fgAPHeadingSet(ap_heading);
419   fgAPAltitudeSet(ap_altitude);
420                                 // GPS overrides heading
421   APDataGlobal->waypoint_hold = ap_gps_lock;
422   APDataGlobal->TargetLatitude = ap_gps_lat;
423   APDataGlobal->TargetLongitude = ap_gps_lon;
424
425   return true;
426 }
427
428 // end of save.cxx