#endif
#include <simgear/constants.h>
+#include <simgear/structure/exception.hxx>
-#include <FDM/flight.hxx>
#include <Main/fg_props.hxx>
#include <Network/native_ctrls.hxx>
#include <Network/native_fdm.hxx>
#include <Network/net_ctrls.hxx>
#include <Network/net_fdm.hxx>
+#include <FDM/fdm_shell.hxx>
#include "replay.hxx"
* Constructor
*/
-FGReplay::FGReplay() {
+FGReplay::FGReplay() :
+ last_replay_state(0)
+{
}
* Destructor
*/
-FGReplay::~FGReplay() {
- // no dynamically allocated memory to free
+FGReplay::~FGReplay()
+{
+ clear();
}
+/**
+ * Clear all internal buffers.
+ */
+void FGReplay::clear()
+{
+ while ( !short_term.empty() )
+ {
+ delete short_term.front();
+ short_term.pop_front();
+ }
+ while ( !medium_term.empty() )
+ {
+ delete medium_term.front();
+ medium_term.pop_front();
+ }
+ while ( !long_term.empty() )
+ {
+ delete long_term.front();
+ long_term.pop_front();
+ }
+ while ( !recycler.empty() )
+ {
+ delete recycler.front();
+ recycler.pop_front();
+ }
+}
/**
* Initialize the data structures
*/
-void FGReplay::init() {
+void FGReplay::init()
+{
+ disable_replay = fgGetNode( "/sim/replay/disable", true );
+ replay_master = fgGetNode( "/sim/freeze/replay-state", true );
+ replay_time = fgGetNode( "/sim/replay/time", true);
+ reinit();
+}
+
+/**
+ * Reset replay queues.
+ */
+
+void FGReplay::reinit()
+{
sim_time = 0.0;
last_mt_time = 0.0;
last_lt_time = 0.0;
// Make sure all queues are flushed
- while ( !short_term.empty() ) {
- short_term.pop_front();
- }
- while ( !medium_term.empty() ) {
- medium_term.pop_front();
- }
- while ( !medium_term.empty() ) {
- medium_term.pop_front();
+ clear();
+
+ // Create an estimated nr of required ReplayData objects
+ // 120 is an estimated maximum frame rate.
+ int estNrObjects = (int) ((st_list_time*120) + (mt_list_time*mt_dt) +
+ (lt_list_time*lt_dt));
+ for (int i = 0; i < estNrObjects; i++)
+ {
+ recycler.push_back(new FGReplayData);
}
+ replay_master->setIntValue(0);
+ disable_replay->setBoolValue(0);
+ replay_time->setDoubleValue(0);
}
-
/**
* Bind to the property tree
*/
-void FGReplay::bind() {
- disable_replay = fgGetNode( "/sim/replay/disable", true );
+void FGReplay::bind()
+{
}
* Unbind from the property tree
*/
-void FGReplay::unbind() {
+void FGReplay::unbind()
+{
// nothing to unbind
}
* Update the saved data
*/
-void FGReplay::update( double dt ) {
- static SGPropertyNode *replay_master
- = fgGetNode( "/sim/freeze/replay", true );
+void FGReplay::update( double dt )
+{
+ timingInfo.clear();
+ stamp("begin");
+
+ if (( sim_time != 0.0 )&&
+ ( disable_replay->getBoolValue() ))
+ {
+ // we were recording data
+ reinit();
+ }
+
+ int replay_state = replay_master->getIntValue();
- if( disable_replay->getBoolValue() ) {
- if( sim_time != 0.0 ) {
- // we were recording data
- init();
- }
- return;
+ if ((replay_state > 0)&&
+ (last_replay_state == 0))
+ {
+ // replay is starting, suspend FDM
+ /* FIXME we need to suspend/resume the FDM - not the entire FDM shell.
+ * FDM isn't available via the global subsystem manager yet, so need a
+ * method at the FDMshell for now */
+ ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->suspend();
+ }
+ else
+ if ((replay_state == 0)&&
+ (last_replay_state > 0))
+ {
+ // replay is finished, resume FDM
+ ((FDMShell*) globals->get_subsystem("flight"))->getFDM()->resume();
}
- if ( replay_master->getBoolValue() ) {
- // don't record the replay session
- return;
+ // remember recent state
+ last_replay_state = replay_state;
+
+ switch(replay_state)
+ {
+ case 0:
+ // replay inactive, keep recording
+ break;
+ case 1:
+ // replay active
+ replay( replay_time->getDoubleValue() );
+ replay_time->setDoubleValue( replay_time->getDoubleValue()
+ + ( dt * fgGetInt("/sim/speed-up") ) );
+ return; // don't record the replay session
+ case 2:
+ // replay paused, no-op
+ return; // don't record the replay session
+ default:
+ throw sg_range_exception("unknown FGReplay state");
}
+ // flight recording
+
+ //cerr << "Recording replay" << endl;
sim_time += dt;
// build the replay record
- FGNetFDM f;
- FGProps2NetFDM( &f, false );
+ //FGNetFDM f;
+ //FGProps2NetFDM( &f, false );
// sanity check, don't collect data if FDM data isn't good
- if ( !cur_fdm_state->get_inited() ) {
+ if (!fgGetBool("/sim/fdm-initialized", false)) {
return;
}
+
+ //FGNetCtrls c;
+ //FGProps2NetCtrls( &c, false, false );
+ //stamp("point_04ba");
+ FGReplayData *r;
+ //stamp("point_04bb");
+ if (!recycler.size()) {
+ stamp("Replay_01");
+ r = new FGReplayData;
+ stamp("Replay_02");
+ } else {
+ r = recycler.front();
+ recycler.pop_front();
+ //stamp("point_04be");
+ }
- FGNetCtrls c;
- FGProps2NetCtrls( &c, false, false );
-
- FGReplayData r;
- r.sim_time = sim_time;
- r.ctrls = c;
- r.fdm = f;
+ r->sim_time = sim_time;
+ //r->ctrls = c;
+ //stamp("point_04e");
+ FGProps2NetFDM( &(r->fdm), false );
+ FGProps2NetCtrls( &(r->ctrls), false, false );
+ //r->fdm = f;
+ //stamp("point_05");
// update the short term list
+ //stamp("point_06");
short_term.push_back( r );
-
- FGReplayData st_front = short_term.front();
- if ( sim_time - st_front.sim_time > st_list_time ) {
- while ( sim_time - st_front.sim_time > st_list_time ) {
+ //stamp("point_07");
+ FGReplayData *st_front = short_term.front();
+ if ( sim_time - st_front->sim_time > st_list_time ) {
+ while ( sim_time - st_front->sim_time > st_list_time ) {
st_front = short_term.front();
+ recycler.push_back(st_front);
short_term.pop_front();
}
-
+ //stamp("point_08");
// update the medium term list
if ( sim_time - last_mt_time > mt_dt ) {
last_mt_time = sim_time;
+ st_front = short_term.front();
medium_term.push_back( st_front );
+ short_term.pop_front();
- FGReplayData mt_front = medium_term.front();
- if ( sim_time - mt_front.sim_time > mt_list_time ) {
- while ( sim_time - mt_front.sim_time > mt_list_time ) {
+ FGReplayData *mt_front = medium_term.front();
+ if ( sim_time - mt_front->sim_time > mt_list_time ) {
+ //stamp("point_09");
+ while ( sim_time - mt_front->sim_time > mt_list_time ) {
mt_front = medium_term.front();
+ recycler.push_back(mt_front);
medium_term.pop_front();
}
-
// update the long term list
if ( sim_time - last_lt_time > lt_dt ) {
last_lt_time = sim_time;
+ mt_front = medium_term.front();
long_term.push_back( mt_front );
+ medium_term.pop_front();
- FGReplayData lt_front = long_term.front();
- if ( sim_time - lt_front.sim_time > lt_list_time ) {
- while ( sim_time - lt_front.sim_time > lt_list_time ) {
+ FGReplayData *lt_front = long_term.front();
+ if ( sim_time - lt_front->sim_time > lt_list_time ) {
+ //stamp("point_10");
+ while ( sim_time - lt_front->sim_time > lt_list_time ) {
lt_front = long_term.front();
+ recycler.push_back(lt_front);
long_term.pop_front();
}
}
<< " time = " << sim_time - long_term.front().sim_time
<< endl;
#endif
+ //stamp("point_finished");
}
return;
} else if ( list.size() == 1 ) {
// handle list size == 1
- update_fdm( list[0] );
+ update_fdm( (*list[0]) );
return;
}
// cout << " " << first << " <=> " << last << endl;
if ( last == first ) {
done = true;
- } else if ( list[mid].sim_time < time && list[mid+1].sim_time < time ) {
+ } else if ( list[mid]->sim_time < time && list[mid+1]->sim_time < time ) {
// too low
first = mid;
mid = ( last + first ) / 2;
- } else if ( list[mid].sim_time > time && list[mid+1].sim_time > time ) {
+ } else if ( list[mid]->sim_time > time && list[mid+1]->sim_time > time ) {
// too high
last = mid;
mid = ( last + first ) / 2;
}
}
- FGReplayData result = interpolate( time, list[mid], list[mid+1] );
+ FGReplayData result = interpolate( time, (*list[mid]), (*list[mid+1]) );
update_fdm( result );
}
double t1, t2;
if ( short_term.size() > 0 ) {
- t1 = short_term.back().sim_time;
- t2 = short_term.front().sim_time;
+ t1 = short_term.back()->sim_time;
+ t2 = short_term.front()->sim_time;
if ( time > t1 ) {
// replay the most recent frame
- update_fdm( short_term.back() );
+ update_fdm( (*short_term.back()) );
// cout << "first frame" << endl;
} else if ( time <= t1 && time >= t2 ) {
interpolate( time, short_term );
// cout << "from short term" << endl;
} else if ( medium_term.size() > 0 ) {
- t1 = short_term.front().sim_time;
- t2 = medium_term.back().sim_time;
+ t1 = short_term.front()->sim_time;
+ t2 = medium_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) {
FGReplayData result = interpolate( time,
- medium_term.back(),
- short_term.front() );
+ (*medium_term.back()),
+ (*short_term.front()) );
update_fdm( result );
// cout << "from short/medium term" << endl;
} else {
- t1 = medium_term.back().sim_time;
- t2 = medium_term.front().sim_time;
+ t1 = medium_term.back()->sim_time;
+ t2 = medium_term.front()->sim_time;
if ( time <= t1 && time >= t2 ) {
interpolate( time, medium_term );
// cout << "from medium term" << endl;
} else if ( long_term.size() > 0 ) {
- t1 = medium_term.front().sim_time;
- t2 = long_term.back().sim_time;
+ t1 = medium_term.front()->sim_time;
+ t2 = long_term.back()->sim_time;
if ( time <= t1 && time >= t2 ) {
FGReplayData result = interpolate( time,
- long_term.back(),
- medium_term.front());
+ (*long_term.back()),
+ (*medium_term.front()));
update_fdm( result );
// cout << "from medium/long term" << endl;
} else {
- t1 = long_term.back().sim_time;
- t2 = long_term.front().sim_time;
+ t1 = long_term.back()->sim_time;
+ t2 = long_term.front()->sim_time;
if ( time <= t1 && time >= t2 ) {
interpolate( time, long_term );
// cout << "from long term" << endl;
} else {
// replay the oldest long term frame
- update_fdm( long_term.front() );
+ update_fdm( (*long_term.front()) );
// cout << "oldest long term frame" << endl;
}
}
} else {
// replay the oldest medium term frame
- update_fdm( medium_term.front() );
+ update_fdm( (*medium_term.front()) );
// cout << "oldest medium term frame" << endl;
}
}
} else {
// replay the oldest short term frame
- update_fdm( short_term.front() );
+ update_fdm( (*short_term.front()) );
// cout << "oldest short term frame" << endl;
}
} else {
double FGReplay::get_start_time() {
if ( long_term.size() > 0 ) {
- return long_term.front().sim_time;
+ return (*long_term.front()).sim_time;
} else if ( medium_term.size() > 0 ) {
- return medium_term.front().sim_time;
+ return (*medium_term.front()).sim_time;
} else if ( short_term.size() ) {
- return short_term.front().sim_time;
+ return (*short_term.front()).sim_time;
} else {
return 0.0;
}
double FGReplay::get_end_time() {
if ( short_term.size() ) {
- return short_term.back().sim_time;
+ return (*short_term.back()).sim_time;
} else {
return 0.0;
}