stk-code_catmod/src/replay_player.cpp

190 lines
5.3 KiB
C++
Raw Normal View History

// $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 3
// 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