// $Id$ // // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2007 Maik Semder // // 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 #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