diff --git a/src/moveable.hpp b/src/moveable.hpp index 087acf1a0..f546785ba 100644 --- a/src/moveable.hpp +++ b/src/moveable.hpp @@ -68,6 +68,7 @@ public: int isOnGround () {return m_on_ground; } sgCoord* getVelocity () {return & m_velocity; } sgCoord* getCoord () {return &m_curr_pos; } + const sgCoord* getCoord () const {return &m_curr_pos; } const sgVec4* getNormalHOT () const {return m_normal_hot; } void setCoord (sgCoord* pos) {sgCopyCoord ( &m_curr_pos,pos); } virtual void placeModel () {m_model->setTransform(&m_curr_pos); } diff --git a/src/replay_base.hpp b/src/replay_base.hpp index f946d49f3..d9ad70b4f 100644 --- a/src/replay_base.hpp +++ b/src/replay_base.hpp @@ -40,7 +40,7 @@ struct ReplayFrame // absolute time of frame float time; // for each kart in frame, points to continious block - // in Buffers::m_pp_blocks_kart_states with m_number_cars items + // in Buffers::m_pp_blocks_kart_states with m_number_karts items ReplayKartState *p_kart_states; }; diff --git a/src/replay_buffers.cpp b/src/replay_buffers.cpp index e58f981b1..14a773241 100644 --- a/src/replay_buffers.cpp +++ b/src/replay_buffers.cpp @@ -6,9 +6,10 @@ #include "replay_base.hpp" #include "replay_buffers.hpp" +#define REPLAY_SAVE_STATISTIC ReplayBuffers::ReplayBuffers() -: m_number_cars(0), +: m_number_karts(0), m_BufferFrame(), m_BufferKartState() { @@ -23,16 +24,16 @@ void ReplayBuffers::destroy() { m_BufferFrame.destroy(); m_BufferKartState.destroy(); - m_number_cars = 0; + m_number_karts = 0; } -bool ReplayBuffers::init( unsigned int number_cars, +bool ReplayBuffers::init( unsigned int number_karts, size_t number_preallocated_frames ) { - m_number_cars = number_cars; + m_number_karts = number_karts; if( !m_BufferFrame.init( number_preallocated_frames ) ) return false; - if( !m_BufferKartState.init( number_preallocated_frames, number_cars ) ) return false; + if( !m_BufferKartState.init( number_preallocated_frames, number_karts ) ) return false; return true; } @@ -63,6 +64,10 @@ bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const if( fprintf( fd, "frames: %u\n", getNumberFrames() ) < 1 ) return false; +#ifdef REPLAY_SAVE_STATISTIC + float time_step_min = 9999999.0f, time_step_max = 0.0f, time_last; +#endif + unsigned int frame_idx, kart_idx; ReplayFrame const *frame; ReplayKartState const *kart; @@ -71,7 +76,7 @@ bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const frame = getFrameAt( frame_idx ); if( fprintf( fd, "frame %u time %f\n", frame_idx, frame->time ) < 1 ) return false; - for( kart_idx = 0; kart_idx < m_number_cars; ++kart_idx ) + for( kart_idx = 0; kart_idx < m_number_karts; ++kart_idx ) { kart = frame->p_kart_states + kart_idx; @@ -79,18 +84,42 @@ bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const kart->position.xyz[0], kart->position.xyz[1], kart->position.xyz[2], kart->position.hpr[0], kart->position.hpr[1], kart->position.hpr[2] ) < 1 ) return false; } + +#ifdef REPLAY_SAVE_STATISTIC + if( frame_idx ) + { + float diff = frame->time - time_last; + if( diff < time_step_min ) time_step_min = diff; + if( diff > time_step_max ) time_step_max = diff; + } + time_last = frame->time; +#endif } +#ifdef REPLAY_SAVE_STATISTIC + float time_step_avg; + if( getNumberFrames() > 1 ) + { + time_step_avg = time_last / ( getNumberFrames() - 1 ); + } + else + { + time_step_avg = -1.0f; + } + fprintf( fd, "\n# statistic time-steps:\n# \tmin: %f\n# \tmax: %f\n# \tavg: %f\n", time_step_min, time_step_max, time_step_avg ); +#endif + return true; } -bool ReplayBuffers::loadReplayHumanReadable( FILE *fd, size_t number_cars ) +bool ReplayBuffers::loadReplayHumanReadable( FILE *fd, unsigned int number_karts ) { size_t frames; if( fscanf( fd, "frames: %u\n", &frames ) != 1 ) return false; - if( !init( number_cars, frames ) ) return false; + if( !init( number_karts, frames ) ) return false; + assert( m_number_karts ); unsigned int frame_idx, kart_idx, tmp; ReplayFrame *frame; ReplayKartState *kart; @@ -102,7 +131,7 @@ bool ReplayBuffers::loadReplayHumanReadable( FILE *fd, size_t number_cars ) if( fscanf( fd, "frame %u time %f\n", &tmp, &frame->time ) != 2 ) return false; - for( kart_idx = 0; kart_idx < number_cars; ++kart_idx ) + for( kart_idx = 0; kart_idx < m_number_karts; ++kart_idx ) { kart = frame->p_kart_states + kart_idx; diff --git a/src/replay_buffers.hpp b/src/replay_buffers.hpp index ab63f9199..6fddecd44 100644 --- a/src/replay_buffers.hpp +++ b/src/replay_buffers.hpp @@ -40,7 +40,7 @@ public: ReplayBuffers(); ~ReplayBuffers(); - bool init( unsigned int number_cars, + bool init( unsigned int number_karts, size_t number_preallocated_frames ); void destroy(); @@ -54,9 +54,10 @@ public: ReplayFrame const* getFrameAt( size_t frame_index ) const { return m_BufferFrame.getObjectAt( frame_index ); } size_t getNumberFrames() const { return m_BufferFrame.getNumberObjectsUsed(); } + unsigned int getNumberKarts() const { return m_number_karts; } bool saveReplayHumanReadable( FILE *fd ) const; - bool loadReplayHumanReadable( FILE *fd, size_t number_cars ); + bool loadReplayHumanReadable( FILE *fd, unsigned int number_karts ); private: bool isHealthy() const { return m_BufferFrame.isHealthy() && m_BufferKartState.isHealthy(); } @@ -65,7 +66,7 @@ private: typedef Buffer BufferFrame; typedef BufferArray BufferKartState; - unsigned int m_number_cars; + unsigned int m_number_karts; BufferFrame m_BufferFrame; BufferKartState m_BufferKartState; }; diff --git a/src/replay_recorder.cpp b/src/replay_recorder.cpp index 2f186befc..9a51ba4f0 100644 --- a/src/replay_recorder.cpp +++ b/src/replay_recorder.cpp @@ -1,9 +1,11 @@ #ifdef HAVE_GHOST_REPLAY -#include "replay_recorder.hpp" - #include +#include "replay_recorder.hpp" +#include "world.hpp" + +const float ReplayRecorder::REPLAY_TIME_STEP_MIN = 1.0f / (float)ReplayRecorder::REPLAY_FREQUENCY_MAX; ReplayRecorder::ReplayRecorder() : ReplayBase() @@ -20,16 +22,45 @@ void ReplayRecorder::destroy() ReplayBase::destroy(); } -bool ReplayRecorder::initRecorder( unsigned int number_cars, size_t number_preallocated_frames ) +bool ReplayRecorder::initRecorder( unsigned int number_karts, size_t number_preallocated_frames ) { - assert( number_cars ); + assert( number_karts ); destroy(); - if( !m_ReplayBuffers.init( number_cars, number_preallocated_frames ) ) return false; + if( !m_ReplayBuffers.init( number_karts, number_preallocated_frames ) ) return false; return true; } +bool ReplayRecorder::pushFrame() +{ + // we dont record the startphase .. + assert( world->getPhase() != World::START_PHASE ); + assert( world->getNumKarts() == m_ReplayBuffers.getNumberKarts() ); + + // make sure we're not under time-step-min + if( m_ReplayBuffers.getNumberFrames() ) + { + ReplayFrame const *last_Frame = m_ReplayBuffers.getFrameAt( m_ReplayBuffers.getNumberFrames() - 1 ); + if( (world->getClock() - last_Frame->time) < REPLAY_TIME_STEP_MIN ) return true; + } + + ReplayFrame *pFrame = getNewFrame(); + if( !pFrame ) return false; + pFrame->time = world->getClock(); + + Kart const *kart; + int number_karts = world->getNumKarts(); + for( int kart_index = 0; kart_index < number_karts; ++kart_index ) + { + kart = world->getKart( kart_index ); + sgCopyCoord( &( pFrame->p_kart_states[ kart_index ].position ), + kart->getCoord() ); + } + + return true; +} + #endif // HAVE_GHOST_REPLAY diff --git a/src/replay_recorder.hpp b/src/replay_recorder.hpp index ad8db8160..36c59b6be 100644 --- a/src/replay_recorder.hpp +++ b/src/replay_recorder.hpp @@ -33,19 +33,26 @@ class ReplayRecorder : public ReplayBase private: // assuming 10 minutes with 50 frames per second enum { BUFFER_PREALLOCATE_FRAMES = 10 * 50 * 60, }; + enum { REPLAY_FREQUENCY_MAX = 30 }; + // calculated from REPLAY_FREQUENCY_MAX + static const float REPLAY_TIME_STEP_MIN; public: ReplayRecorder(); virtual ~ReplayRecorder(); void destroy(); - bool initRecorder( unsigned int number_cars, + bool initRecorder( unsigned int number_karts, size_t number_preallocated_frames = BUFFER_PREALLOCATE_FRAMES ); + // something might go wrong, since a new buffer may be allocated, so false means + // no memory available + bool pushFrame(); + +private: // returns a new *free* frame to be used to store the current frame-data into it // used to *record* the replay ReplayFrame* getNewFrame() { return m_ReplayBuffers.getNewFrame(); } - }; diff --git a/src/world.cpp b/src/world.cpp index fa11c9857..927036cd9 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -395,35 +395,12 @@ void World::update(float delta) // normally, but after switching to RACE_PHASE m_clock is set back to 0.0 if( m_phase != START_PHASE ) { - pushReplayFrameData(); + m_replay_recorder.pushFrame(); if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock ); } #endif } -#ifdef HAVE_GHOST_REPLAY -//----------------------------------------------------------------------------- -void World::pushReplayFrameData() -{ - // we dont record the startphase .. - assert( m_phase != START_PHASE ); - - ReplayFrame *pFrame = m_replay_recorder.getNewFrame(); - if( !pFrame ) return; - - pFrame->time = m_clock; - - Karts::const_iterator itKarts; - int kart_index = 0; - for( itKarts = m_kart.begin(); itKarts != m_kart.end(); ++itKarts, ++kart_index ) - { - sgCopyCoord( &( pFrame->p_kart_states[ kart_index ].position ), - (*itKarts)->getCoord() ); - } - -} // pushFrameData -#endif // HAVE_GHOST_REPLAY - #ifdef HAVE_GHOST_REPLAY //----------------------------------------------------------------------------- bool World::saveReplayHumanReadable( std::string const &filename ) const @@ -528,7 +505,7 @@ void World::checkRaceStatus() sound_manager->playSfx(SOUND_START); #ifdef HAVE_GHOST_REPLAY // push positions at time 0.0 to replay-data - pushReplayFrameData(); + m_replay_recorder.pushFrame(); #endif } else if (m_clock > 1.0 && m_ready_set_go == 2) diff --git a/src/world.hpp b/src/world.hpp index 5373b8cea..ff35d3128 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -127,8 +127,9 @@ private: sgCoord init_pos); #ifdef HAVE_GHOST_REPLAY +public: + float getClock() const { return m_clock; } private: - void pushReplayFrameData(); bool saveReplayHumanReadable( std::string const &filename ) const; bool loadReplayHumanReadable( std::string const &filename );