32b88d2091
- changed name of class "Buffer" to "ReplayBuffer" .. "Buffer" at global scope was not a good idea of mine .. ;) git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1268 178a84e3-b1eb-0310-8ba1-8eac791a3b58
177 lines
5.1 KiB
C++
177 lines
5.1 KiB
C++
// $Id$
|
|
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2007 Maik Semder <ikework@gmx.de>
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
#include <cassert>
|
|
|
|
|
|
#include "replay_base.hpp"
|
|
#include "replay_buffers.hpp"
|
|
|
|
#define REPLAY_SAVE_STATISTIC
|
|
|
|
ReplayBuffers::ReplayBuffers()
|
|
: m_number_karts(0),
|
|
m_BufferFrame(),
|
|
m_BufferKartState()
|
|
{
|
|
}
|
|
|
|
ReplayBuffers::~ReplayBuffers()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
void ReplayBuffers::destroy()
|
|
{
|
|
m_BufferFrame.destroy();
|
|
m_BufferKartState.destroy();
|
|
m_number_karts = 0;
|
|
}
|
|
|
|
bool ReplayBuffers::init( unsigned int number_karts,
|
|
size_t number_preallocated_frames )
|
|
{
|
|
m_number_karts = number_karts;
|
|
|
|
if( !m_BufferFrame.init( number_preallocated_frames ) ) return false;
|
|
if( !m_BufferKartState.init( number_preallocated_frames, number_karts ) ) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
ReplayFrame*
|
|
ReplayBuffers::getNewFrame()
|
|
{
|
|
// make sure initialization was called properly
|
|
assert( m_BufferFrame.getNumberObjectsUsed() == m_BufferKartState.getNumberArraysUsed() );
|
|
|
|
if( !isHealthy() ) return NULL;
|
|
|
|
ReplayFrame* frame = m_BufferFrame.getNewObject();
|
|
if( !frame ) return NULL;
|
|
|
|
// get current karts-array
|
|
ReplayKartState* karts_array = m_BufferKartState.getNewArray();
|
|
if( !karts_array ) return NULL;
|
|
|
|
frame->p_kart_states = karts_array;
|
|
|
|
return frame;
|
|
}
|
|
|
|
bool ReplayBuffers::saveReplayHumanReadable( FILE *fd ) const
|
|
{
|
|
if( !isHealthy() ) return false;
|
|
|
|
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;
|
|
for( frame_idx = 0; frame_idx < getNumberFrames(); ++frame_idx )
|
|
{
|
|
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_karts; ++kart_idx )
|
|
{
|
|
kart = frame->p_kart_states + kart_idx;
|
|
|
|
if( fprintf( fd, "\tkart %u: %f,%f,%f,%f,%f,%f\n", kart_idx,
|
|
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, unsigned int number_karts )
|
|
{
|
|
size_t frames;
|
|
if( fscanf( fd, "frames: %u\n", &frames ) != 1 ) return false;
|
|
|
|
if( !init( number_karts, frames ) ) return false;
|
|
|
|
assert( m_number_karts );
|
|
unsigned int frame_idx, kart_idx, tmp;
|
|
ReplayFrame *frame;
|
|
ReplayKartState *kart;
|
|
for( frame_idx = 0; frame_idx < frames; ++frame_idx )
|
|
{
|
|
// if we are here, it cant fail, since enough objects have to be allocated above
|
|
frame = getNewFrame();
|
|
assert( frame );
|
|
|
|
if( fscanf( fd, "frame %u time %f\n", &tmp, &frame->time ) != 2 ) return false;
|
|
|
|
for( kart_idx = 0; kart_idx < m_number_karts; ++kart_idx )
|
|
{
|
|
kart = frame->p_kart_states + kart_idx;
|
|
|
|
if( fscanf( fd, "\tkart %u: %f,%f,%f,%f,%f,%f\n", &tmp,
|
|
&kart->position.xyz[0], &kart->position.xyz[1], &kart->position.xyz[2],
|
|
&kart->position.hpr[0], &kart->position.hpr[1], &kart->position.hpr[2] ) != 7 ) return false;
|
|
}
|
|
}
|
|
|
|
assert( frames == getNumberFrames() );
|
|
assert( m_BufferFrame.getNumberObjectsUsed() == getNumberFrames() );
|
|
assert( m_BufferKartState.getNumberArraysUsed() == getNumberFrames() );
|
|
|
|
// there should be no reallocation ..
|
|
assert( m_BufferFrame.getNumberBlocks() == 1 );
|
|
assert( m_BufferKartState.getNumberBlocks() == 1 );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
#endif // HAVE_GHOST_REPLAY
|