replay:
* set max. sample-frequency to 30 frames per second * put sample-freq-statistic in the end of replay-file as comments * did some replay-cleaning git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1265 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
c1ed88df9c
commit
0b7cadfbea
@ -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); }
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<ReplayFrame> BufferFrame;
|
||||
typedef BufferArray<ReplayKartState> BufferKartState;
|
||||
|
||||
unsigned int m_number_cars;
|
||||
unsigned int m_number_karts;
|
||||
BufferFrame m_BufferFrame;
|
||||
BufferKartState m_BufferKartState;
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
|
||||
#include "replay_recorder.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#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
|
||||
|
@ -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(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user