// $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 "kart_properties_manager.hpp" #include "kart_properties.hpp" #include "replay_player.hpp" ReplayKart::ReplayKart() : m_kart_properties(NULL), m_model(NULL) { } ReplayKart::~ReplayKart() { destroy(); } void ReplayKart::destroy() { m_kart_properties = NULL; } bool ReplayKart::init( const std::string &strKartIdent ) { assert( !m_kart_properties ); m_model = new ssgTransform(); m_model->ref(); m_kart_properties = kart_properties_manager->getKart( strKartIdent ); if( NULL == m_kart_properties ) return false; ssgEntity *obj = m_kart_properties->getModel(); assert( obj ); // Optimize the model, this can't be done while loading the model // because it seems that it removes the name of the wheels or something // else needed to load the wheels as a separate object. ssgFlatten(obj); ssgRangeSelector *lod = new ssgRangeSelector; float r [ 2 ] = { -10.0f, 100.0f } ; lod -> addKid ( obj ) ; lod -> setRanges ( r, 2 ) ; m_model -> addKid ( lod ) ; return true; } #include "scene.hpp" ReplayPlayer::ReplayPlayer() : ReplayBase(), m_current_frame_index(-1) { } ReplayPlayer::~ReplayPlayer() { destroy(); } void ReplayPlayer::destroy() { m_current_frame_index = -1; m_Karts.clear(); ReplayBase::destroy(); } bool ReplayPlayer::loadReplayHumanReadable( FILE *fd ) { destroy(); bool blnRet = false; int intTemp; char buff[1000]; size_t number_karts; if( fscanf( fd, "Version: %s\n", buff ) != 1 ) return false; if( fscanf( fd, "numkarts: %u\n", &number_karts ) != 1 ) return false; if( fscanf( fd, "numplayers: %s\n", buff ) != 1 ) return false; if( fscanf( fd, "difficulty: %s\n", buff ) != 1 ) return false; if( fscanf( fd, "track: %s\n", buff ) != 1 ) return false; for( size_t k = 0; k < number_karts; ++k ) { if( fscanf( fd, "model %d: %s\n", &intTemp, buff ) != 2 ) return false; m_Karts.resize( m_Karts.size() + 1 ); ReplayKart &kart = m_Karts[ m_Karts.size() - 1 ]; if( !kart.init( buff ) ) return false; scene->add ( kart.getModel() ); } if( !m_ReplayBuffers.loadReplayHumanReadable( fd, number_karts ) ) return false; m_current_frame_index = 0; return true; } void ReplayPlayer::showReplayAt( float abs_time ) { assert( m_ReplayBuffers.getNumberFrames() ); assert( m_current_frame_index > -1 ); assert( (size_t)m_current_frame_index < m_ReplayBuffers.getNumberFrames() ); ReplayFrame const* frame; // find the current frame, we only scroll forward .. while(1) { // end reached? if( (m_current_frame_index + 1) == m_ReplayBuffers.getNumberFrames() ) break; // check time of next frame frame = m_ReplayBuffers.getFrameAt( m_current_frame_index+1 ); if( frame->time > abs_time ) break; ++m_current_frame_index; } frame = m_ReplayBuffers.getFrameAt( m_current_frame_index ); // interpolate, if we are not at the end if( (m_current_frame_index + 1) < (int)m_ReplayBuffers.getNumberFrames() ) { ReplayFrame const* frame_next = m_ReplayBuffers.getFrameAt( m_current_frame_index+1 ); // calc scale factor based on time between frames assert( frame_next->time > frame->time ); assert( frame_next->time != frame->time ); float scale = (abs_time - frame->time) / (frame_next->time - frame->time); sgVec3 tmp_v3; sgCoord pos; // calc interpolations for all objects for( size_t k = 0; k < m_Karts.size(); ++k ) { // calc distance between next and current frame-position sgCopyVec3( pos.xyz, frame->p_kart_states[k].position.xyz ) ; sgCopyVec3( tmp_v3, frame_next->p_kart_states[k].position.xyz ) ; sgSubVec3( tmp_v3, pos.xyz ); // scale it based on time between frames sgScaleVec3( tmp_v3, scale ); // add interpolated vector sgAddVec3( pos.xyz, tmp_v3 ); // no orientation-interpolation for starters sgCopyVec3( pos.hpr, frame->p_kart_states[k].position.hpr ); m_Karts[ k ].setPosition( pos ); } } else { // replay finished, leave them at last known position for( size_t k = 0; k < m_Karts.size(); ++k ) { m_Karts[ k ].setPosition( frame->p_kart_states[ k ].position ); } } } #endif // HAVE_GHOST_REPLAY