1 /*
2  * CRRCsim - the Charles River Radio Control Club Flight Simulator Project
3  *
4  * Copyright (C) 2006-2010 Jan Reucker (original author)
5  * Copyright (C) 2006 Todd Templeton
6  * Copyright (C) 2007, 2008, 2010 Jens Wilhelm Wulf
7  * Copyright (C) 2008 Olivier Bordes
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2
11  * as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24 
25 /** \file SimStateHandler.cpp
26  *
27  *  This file includes the implementation of the class
28  *  SimStateHandler, which takes care of the current
29  *  simulation state (running, paused, ...) and provides
30  *  some handy time values.
31  *
32  *  \author J. Reucker
33  */
34 #include "i18n.h"
35 #include "global.h"
36 #include "aircraft.h"
37 #include "crrc_main.h"
38 #include "crrc_soundserver.h"
39 #include "global_video.h"
40 #include "SimStateHandler.h"
41 #include "mod_mode/T_GameHandler.h"
42 #include "GUI/crrc_gui_main.h"
43 #include "mod_fdm/fdm.h"
44 #include "mod_windfield/windfield.h"
45 #include "robots.h"
46 #include "record.h"
47 #include "mod_misc/lib_conversions.h"
48 
49 
50 /**
51  * Advance the simulation by the specified number om milliseconds
52  */
idle(TSimInputs * inputs,int nDeltaTicks)53 void idle(TSimInputs* inputs, int nDeltaTicks)
54 {
55   static double dDeltaT = 0; // Difference between display and EOM time
56   int multiloop;
57   float timeScale;
58 
59   if (Global::Simulation->getState() == STATE_RESUMING)
60     Global::Simulation->setState(STATE_RUN);
61 
62   // How many times the flight model shall be calculated
63   // given it advances the simulation dt seconds for every step
64   multiloop = (int)((nDeltaTicks/1000.0 - dDeltaT)/Global::dt + 0.5);
65 
66   // alter simulation time scale if slow motion is active
67   if (Global::slowMotion)
68     timeScale = Global::slowTimeScale;
69   else
70     timeScale = 1.0;
71 
72   multiloop /= timeScale;
73   dDeltaT += multiloop*Global::dt - nDeltaTicks/1000.0/timeScale;
74 
75   Global::Simulation->incSimSteps(multiloop);
76 
77   update_thermals(Global::dt * multiloop);
78 
79   Global::aircraft->getFDMInterface()->update(inputs, Global::dt, multiloop);
80   Global::aircraft->getModel()->update(Global::aircraft->getFDM());
81 
82   double X_cg_rwy =    Global::aircraft->getPos().r[0];
83   double Y_cg_rwy =    Global::aircraft->getPos().r[1];
84   double H_cg_rwy = -1*Global::aircraft->getPos().r[2];
85 
86   Global::gameHandler->update(X_cg_rwy,Y_cg_rwy,H_cg_rwy, Global::recorder, Global::robots);
87 
88   Global::recorder->AirplanePosition(Global::dt, multiloop, Global::aircraft->getFDMInterface()->fdm);
89 
90   Global::robots->Update(Global::dt, multiloop);
91 
92   // the camera is still on test_mode
93   if (!Global::testmode)
94     Video::UpdateCamera(Global::dt * multiloop);
95 
96   Global::TXInterface->update(Global::dt * multiloop);
97 }
98 
99 
100 /**
101  *  Creates the state machine.
102  *
103  */
SimStateHandler()104 SimStateHandler::SimStateHandler()
105   : EventListener(Event::Generic),
106     nState(STATE_RESUMING), IdleFunc(idle), OldIdleFunc(NULL),
107     sim_steps(0), pause_time(0), accum_pause_time(0), reset_time(0)
108 {
109 }
110 
111 
112 /**
113  *  Destroys the state machine.
114  *
115  */
~SimStateHandler()116 SimStateHandler::~SimStateHandler()
117 {
118 }
119 
120 
121 /**
122  *  Leaves the PAUSED state and continues the simulation.
123  *
124  */
resume()125 void SimStateHandler::resume()
126 {
127   if (nState != STATE_CRASHED)
128   {
129     nState = STATE_RESUMING;
130 
131     // add the time we spent in pause mode to the
132     // accumulated pause time counter
133     accum_pause_time += SDL_GetTicks() - pause_time;
134 
135     if (Global::soundserver != NULL)
136     {
137       Global::soundserver->pause(false);
138     }
139     LOG(_("Resuming."));
140   }
141 }
142 
143 
144 /**
145  *  Pauses the simulation and stops the sound server.
146  *
147  */
pause()148 void SimStateHandler::pause()
149 {
150   if ((nState != STATE_PAUSED) && (nState != STATE_CRASHED))
151   {
152     // entering pause mode from a different mode
153     nState = STATE_PAUSED;
154     pause_time = SDL_GetTicks();
155   }
156   if (Global::soundserver != NULL)
157   {
158     Global::soundserver->pause(true);
159   }
160   if (nState == STATE_PAUSED)
161   {
162     LOG(_("Simulation paused."));
163   }
164 }
165 
166 
167 /**
168  *  Resets the simulation, re-initializes the flight
169  *  dynamics model and restarts the currently running
170  *  game (if any).
171  */
reset()172 void SimStateHandler::reset()
173 {
174   unsigned long int current;
175 
176   Global::inputs = TSimInputs();
177 
178   if (Global::testmode)
179     leave_test_mode();
180 
181   sim_steps = 0;
182 
183   current = SDL_GetTicks();
184   reset_time = current;
185   pause_time = current;
186   accum_pause_time = 0;
187 
188   /*
189   IdleFunc = idle;
190   OldIdleFunc = NULL;
191   */
192 
193   nState = STATE_RESUMING;
194   initialize_flight_model();
195   Init_mod_windfield();
196 
197   Global::aircraft->getModel()->reset(Global::aircraft->getFDM());
198   Global::gameHandler->reset();
199   Global::robots->Reset();
200   Global::TXInterface->reset();
201 
202   Video::InitSmartCamera();
203 
204   LOG(_("Simulation reset."));
205 }
206 
207 
208 /**
209  *  Causes the simulation to terminate after the
210  *  current frame.
211  */
quit()212 void SimStateHandler::quit()
213 {
214   nState = STATE_EXIT;
215 }
216 
217 
218 /**
219  * Handle a crash
220  */
crash()221 void SimStateHandler::crash()
222 {
223   if (nState != STATE_CRASHED)
224   {
225     // entering pause mode from a different mode
226     nState = STATE_CRASHED;
227     if (Global::soundserver != NULL)
228     {
229       Global::soundserver->pause(true);
230     }
231 
232     LOG(_("Plane crashed."));
233   }
234 }
235 
236 
237 /**
238  *  Interface to the event dispatcher
239  */
operator ()(const Event * ev)240 void SimStateHandler::operator()(const Event* ev)
241 {
242   if (ev->getType() == Event::CrashEvent)
243   {
244     crash();
245   }
246 }
247 
248 
249 /**
250  *  Run conditionnaly the "idle" function.
251  *
252  *  \param in Collection of current control input values.
253  */
doIdle(TSimInputs * in,int deltaT)254 void SimStateHandler::doIdle(TSimInputs* in, int deltaT)
255 {
256   if (Global::gui && Global::gui->isVisible()) Global::gui->GUI_IdleFunction(in);
257 
258   if (Global::testmode)
259     idle(in, deltaT);
260   else if (
261       (nState != STATE_EXIT) &&
262       (nState != STATE_PAUSED) &&
263       (nState != STATE_CRASHED))
264   {
265     idle(in, deltaT);
266   }
267 }
268 
269 
270 #if 0
271 Functions not used at present. To delete ?
272 /**
273  *  Register a new idle function. The old idle function
274  *  will be saved and can be restored by calling resetIdle().
275  *
276  *  \param new_idle Pointer to the new idle function
277  */
278 void SimStateHandler::setNewIdle(TIdleFuncPtr new_idle)
279 {
280   OldIdleFunc = IdleFunc;
281   IdleFunc = new_idle;
282 }
283 
284 
285 /**
286  *  Restore the previous idle function.
287  *
288  */
289 void SimStateHandler::resetIdle()
290 {
291   if (OldIdleFunc != NULL)
292   {
293     IdleFunc = OldIdleFunc;
294     OldIdleFunc = NULL;
295   }
296 }
297 #endif
298 
299 
300 /**
301  *  Returns the elapsed time since the last reset(),
302  *  in milliseconds.
303  *
304  *  \return milliseconds since last reset
305  */
getTotalTimeSinceReset()306 unsigned long int SimStateHandler::getTotalTimeSinceReset()
307 {
308   return (SDL_GetTicks() - reset_time);
309 }
310 
311 
312 /**
313  *  Returns the elapsed time since the last reset(),
314  *  but not counting the time spent in PAUSE mode.
315  *
316  *  \return unpaused time since last reset
317  */
getGameTimeSinceReset()318 unsigned long int SimStateHandler::getGameTimeSinceReset()
319 {
320   unsigned long int total_pause;
321   unsigned long int current;
322 
323   current = SDL_GetTicks();
324   total_pause = accum_pause_time;
325   if (nState == STATE_PAUSED)
326   {
327     total_pause += current - pause_time;
328   }
329   return (current - (total_pause + reset_time));
330 }
331 
332 
333 /**
334  *  Returns the simulation time since the last reset()
335  *  (number of sim steps * dt, in ms)
336  *
337  *  \return simulation time since last reset
338  */
getSimulationTimeSinceReset()339 unsigned long int SimStateHandler::getSimulationTimeSinceReset()
340 {
341   return (unsigned long int)(sim_steps*Global::dt*1000);
342 }
343