diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_sceneentity.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_sceneentity.cpp')
| -rw-r--r-- | mp/src/game/client/c_sceneentity.cpp | 2420 |
1 files changed, 1210 insertions, 1210 deletions
diff --git a/mp/src/game/client/c_sceneentity.cpp b/mp/src/game/client/c_sceneentity.cpp index d56a67c8..b44b59fd 100644 --- a/mp/src/game/client/c_sceneentity.cpp +++ b/mp/src/game/client/c_sceneentity.cpp @@ -1,1211 +1,1211 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "networkstringtable_clientdll.h"
-#include "dt_utlvector_recv.h"
-#include "choreoevent.h"
-#include "choreoactor.h"
-#include "choreochannel.h"
-#include "filesystem.h"
-#include "ichoreoeventcallback.h"
-#include "scenefilecache/ISceneFileCache.h"
-#include "materialsystem/imaterialsystemhardwareconfig.h"
-#include "tier2/tier2.h"
-#include "hud_closecaption.h"
-#include "tier0/icommandline.h"
-
-#include "c_sceneentity.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-//-----------------------------------------------------------------------------
-// Purpose: Decodes animtime and notes when it changes
-// Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine
-// *pVarData -
-// *pIn -
-// objectID -
-//-----------------------------------------------------------------------------
-void RecvProxy_ForcedClientTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
-{
- C_SceneEntity *pScene = reinterpret_cast< C_SceneEntity * >( pStruct );
- *(float *)pOut = pData->m_Value.m_Float;
- pScene->OnResetClientTime();
-}
-
-#if defined( CSceneEntity )
-#undef CSceneEntity
-#endif
-
-IMPLEMENT_CLIENTCLASS_DT(C_SceneEntity, DT_SceneEntity, CSceneEntity)
- RecvPropInt(RECVINFO(m_nSceneStringIndex)),
- RecvPropBool(RECVINFO(m_bIsPlayingBack)),
- RecvPropBool(RECVINFO(m_bPaused)),
- RecvPropBool(RECVINFO(m_bMultiplayer)),
- RecvPropFloat(RECVINFO(m_flForceClientTime), 0, RecvProxy_ForcedClientTime ),
- RecvPropUtlVector(
- RECVINFO_UTLVECTOR( m_hActorList ),
- MAX_ACTORS_IN_SCENE,
- RecvPropEHandle(NULL, 0, 0)),
-END_RECV_TABLE()
-
-C_SceneEntity::C_SceneEntity( void )
-{
- m_pScene = NULL;
- m_bMultiplayer = false;
-
- m_hOwner = NULL;
- m_bClientOnly = false;
-}
-
-C_SceneEntity::~C_SceneEntity( void )
-{
- UnloadScene();
-}
-
-void C_SceneEntity::OnResetClientTime()
-{
- // In TF2 we ignore this as the scene is played entirely client-side.
-#ifndef TF_CLIENT_DLL
- m_flCurrentTime = m_flForceClientTime;
-#endif
-}
-
-char const *C_SceneEntity::GetSceneFileName()
-{
- return g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex );
-}
-
-ConVar mp_usehwmvcds( "mp_usehwmvcds", "0", NULL, "Enable the use of the hw morph vcd(s). (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always
-bool UseHWMorphVCDs()
-{
-// if ( mp_usehwmvcds.GetInt() == 0 )
-// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
-// return mp_usehwmvcds.GetInt() > 0;
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool C_SceneEntity::GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename )
-{
- // Are we even using hardware morph?
- if ( !UseHWMorphVCDs() )
- return false;
-
- // Multi-player only!
- if ( !m_bMultiplayer )
- return false;
-
- // Do we have a valid filename?
- if ( !( pFilename && pFilename[0] ) )
- return false;
-
- // Check to see if we already have an player/hwm/* filename.
- if ( ( V_strstr( pFilename, "/high" ) != NULL ) || ( V_strstr( pFilename, "\\high" ) != NULL ) )
- {
- V_strcpy( pHWMFilename, pFilename );
- return true;
- }
-
- // Find the hardware morph scene name and pass that along as well.
- char szScene[MAX_PATH];
- V_strcpy( szScene, pFilename );
-
- char szSceneHWM[MAX_PATH];
- szSceneHWM[0] = '\0';
-
- char *pszToken = strtok( szScene, "/\\" );
- while ( pszToken != NULL )
- {
- if ( !V_stricmp( pszToken, "low" ) )
- {
- V_strcat( szSceneHWM, "high", sizeof( szSceneHWM ) );
- }
- else
- {
- V_strcat( szSceneHWM, pszToken, sizeof( szSceneHWM ) );
- }
-
- pszToken = strtok( NULL, "/\\" );
- if ( pszToken != NULL )
- {
- V_strcat( szSceneHWM, "\\", sizeof( szSceneHWM ) );
- }
- }
-
- V_strcpy( pHWMFilename, szSceneHWM );
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::ResetActorFlexesForScene()
-{
- int nActorCount = m_pScene->GetNumActors();
- for( int iActor = 0; iActor < nActorCount; ++iActor )
- {
- CChoreoActor *pChoreoActor = m_pScene->GetActor( iActor );
- if ( !pChoreoActor )
- continue;
-
- C_BaseFlex *pFlexActor = FindNamedActor( pChoreoActor );
- if ( !pFlexActor )
- continue;
-
- CStudioHdr *pStudioHdr = pFlexActor->GetModelPtr();
- if ( !pStudioHdr )
- continue;
-
- if ( pStudioHdr->numflexdesc() == 0 )
- continue;
-
- // Reset the flex weights to their starting position.
- LocalFlexController_t iController;
- for ( iController = LocalFlexController_t(0); iController < pStudioHdr->numflexcontrollers(); ++iController )
- {
- pFlexActor->SetFlexWeight( iController, 0.0f );
- }
-
- // Reset the prediction interpolation values.
- pFlexActor->m_iv_flexWeight.Reset();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::StopClientOnlyScene()
-{
- if ( m_pScene )
- {
- m_pScene->ResetSimulation();
-
- if ( m_hOwner.Get() )
- {
- m_hOwner->RemoveChoreoScene( m_pScene );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner /* = NULL */, bool bMultiplayer /* = false */ )
-{
- m_bIsPlayingBack = true;
- m_bMultiplayer = bMultiplayer;
- m_hOwner = pOwner;
- m_bClientOnly = true;
-
- char szFilename[128];
- Assert( V_strlen( pszFilename ) < 128 );
- V_strcpy( szFilename, pszFilename );
-
- char szSceneHWM[128];
- if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) )
- {
- V_strcpy( szFilename, szSceneHWM );
- }
-
- Assert( szFilename && szFilename[ 0 ] );
- if ( szFilename && szFilename[ 0 ] )
- {
- LoadSceneFromFile( szFilename );
-
- if (!CommandLine()->FindParm("-hushasserts"))
- {
- Assert( m_pScene );
- }
-
- // Should handle gestures and sequences client side.
- if ( m_bMultiplayer )
- {
- if ( m_pScene )
- {
- int types[6];
- types[0] = CChoreoEvent::FLEXANIMATION;
- types[1] = CChoreoEvent::EXPRESSION;
- types[2] = CChoreoEvent::GESTURE;
- types[3] = CChoreoEvent::SEQUENCE;
- types[4] = CChoreoEvent::SPEAK;
- types[5] = CChoreoEvent::LOOP;
- m_pScene->RemoveEventsExceptTypes( types, 6 );
- }
-
- PrefetchAnimBlocks( m_pScene );
- }
- else
- {
- if ( m_pScene )
- {
- int types[ 2 ];
- types[ 0 ] = CChoreoEvent::FLEXANIMATION;
- types[ 1 ] = CChoreoEvent::EXPRESSION;
- m_pScene->RemoveEventsExceptTypes( types, 2 );
- }
- }
-
- SetNextClientThink( CLIENT_THINK_ALWAYS );
- }
-
- if ( m_hOwner.Get() )
- {
- if (!CommandLine()->FindParm("-hushasserts"))
- {
- Assert( m_pScene );
- }
-
- if ( m_pScene )
- {
- ClearSceneEvents( m_pScene, false );
-
- if ( m_bIsPlayingBack )
- {
- m_pScene->ResetSimulation();
- m_hOwner->StartChoreoScene( m_pScene );
- }
- else
- {
- m_pScene->ResetSimulation();
- m_hOwner->RemoveChoreoScene( m_pScene );
- }
-
- // Reset the flex weights when we start a new scene. This is normally done on the player model, but since
- // we don't have a player here yet - we need to do this!
- ResetActorFlexesForScene();
- }
- }
- else
- {
- for( int i = 0; i < m_hActorList.Count() ; ++i )
- {
- C_BaseFlex *actor = m_hActorList[ i ].Get();
- if ( !actor )
- continue;
-
- Assert( m_pScene );
-
- if ( m_pScene )
- {
- ClearSceneEvents( m_pScene, false );
-
- if ( m_bIsPlayingBack )
- {
- m_pScene->ResetSimulation();
- actor->StartChoreoScene( m_pScene );
- }
- else
- {
- m_pScene->ResetSimulation();
- actor->RemoveChoreoScene( m_pScene );
- }
- }
- }
- }
-}
-
-void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType )
-{
- BaseClass::PostDataUpdate( updateType );
-
- char const *str = GetSceneFileName();
- char szFilename[MAX_PATH];
- if ( str )
- {
- Assert( V_strlen( str ) < MAX_PATH );
- V_strcpy( szFilename, str );
- }
- else
- {
- szFilename[0] = '\0';
- }
-
- char szSceneHWM[MAX_PATH];
- if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) )
- {
- V_strcpy( szFilename, szSceneHWM );
- }
-
- if ( updateType == DATA_UPDATE_CREATED )
- {
- Assert( szFilename && szFilename[ 0 ] );
- if ( szFilename && szFilename[ 0 ] )
- {
- LoadSceneFromFile( szFilename );
-
- // Kill everything except flex events
- Assert( m_pScene );
-
- // Should handle gestures and sequences clientside.
- if ( m_bMultiplayer )
- {
- if ( m_pScene )
- {
- int types[6];
- types[0] = CChoreoEvent::FLEXANIMATION;
- types[1] = CChoreoEvent::EXPRESSION;
- types[2] = CChoreoEvent::GESTURE;
- types[3] = CChoreoEvent::SEQUENCE;
- types[4] = CChoreoEvent::SPEAK;
- types[5] = CChoreoEvent::LOOP;
- m_pScene->RemoveEventsExceptTypes( types, 6 );
- }
-
- PrefetchAnimBlocks( m_pScene );
- }
- else
- {
- if ( m_pScene )
- {
- int types[ 2 ];
- types[ 0 ] = CChoreoEvent::FLEXANIMATION;
- types[ 1 ] = CChoreoEvent::EXPRESSION;
- m_pScene->RemoveEventsExceptTypes( types, 2 );
- }
- }
-
- SetNextClientThink( CLIENT_THINK_ALWAYS );
- }
- }
-
- // Playback state changed...
- if ( m_bWasPlaying != m_bIsPlayingBack )
- {
- for(int i = 0; i < m_hActorList.Count() ; ++i )
- {
- C_BaseFlex *actor = m_hActorList[ i ].Get();
- if ( !actor )
- continue;
-
- Assert( m_pScene );
-
- if ( m_pScene )
- {
- ClearSceneEvents( m_pScene, false );
-
- if ( m_bIsPlayingBack )
- {
- m_pScene->ResetSimulation();
- actor->StartChoreoScene( m_pScene );
- }
- else
- {
- m_pScene->ResetSimulation();
- actor->RemoveChoreoScene( m_pScene );
- }
- }
- }
- }
-}
-
-void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType )
-{
- BaseClass::PreDataUpdate( updateType );
-
- m_bWasPlaying = m_bIsPlayingBack;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Called every frame that an event is active (Start/EndEvent as also
-// called)
-// Input : *event -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
-{
- // For now we only need to process events if we go back in time.
- if ( currenttime < event->m_flPrevTime )
- {
- //if ( !V_strstr( scene->GetFilename(), "idleloop" ) )
- //{
- // Msg( "ProcessEvent( %6.4f, %32s %6.4f ) %6.4f\n", currenttime, event->GetName(), event->m_flPrevTime, m_flCurrentTime );
- //}
-
- C_BaseFlex *pActor = NULL;
- CChoreoActor *actor = event->GetActor();
- if ( actor )
- {
- pActor = FindNamedActor( actor );
- if ( NULL == pActor )
- {
- // TODO: QueueProcessEvent
- // This can occur if we haven't been networked an actor yet... we need to queue it so that we can
- // fire off the process event as soon as we have the actor resident on the client.
- return;
- }
- }
-
- switch ( event->GetType() )
- {
- case CChoreoEvent::GESTURE:
- {
- // Verify data.
- Assert( m_bMultiplayer );
- Assert( scene != NULL );
- Assert( event != NULL );
-
- if ( pActor )
- {
- DispatchProcessGesture( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::SEQUENCE:
- {
- // Verify data.
- Assert( m_bMultiplayer );
- Assert( scene != NULL );
- Assert( event != NULL );
-
- if ( pActor )
- {
- DispatchProcessSequence( scene, pActor, event );
- }
- }
- break;
- }
- }
-
- event->m_flPrevTime = currenttime;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Called for events that are part of a pause condition
-// Input : *event -
-// Output : Returns true on event completed, false on non-completion.
-//-----------------------------------------------------------------------------
-bool C_SceneEntity::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
-{
- return true;
-}
-
-C_BaseFlex *C_SceneEntity::FindNamedActor( CChoreoActor *pChoreoActor )
-{
- if ( !m_pScene )
- return NULL;
-
- if ( m_hOwner.Get() != NULL )
- {
- return m_hOwner.Get();
- }
-
- int idx = m_pScene->FindActorIndex( pChoreoActor );
- if ( idx < 0 || idx >= m_hActorList.Count() )
- return NULL;
-
- return m_hActorList[ idx ].Get();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: All events are leading edge triggered
-// Input : currenttime -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
-{
- Assert( event );
-
- if ( !Q_stricmp( event->GetName(), "NULL" ) )
- {
- Scene_Printf( "%s : %8.2f: ignored %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
- return;
- }
-
-
- C_BaseFlex *pActor = NULL;
- CChoreoActor *actor = event->GetActor();
- if ( actor )
- {
- pActor = FindNamedActor( actor );
- if ( NULL == pActor )
- {
- // This can occur if we haven't been networked an actor yet... we need to queue it so that we can
- // fire off the start event as soon as we have the actor resident on the client.
- QueueStartEvent( currenttime, scene, event );
- return;
- }
- }
-
- Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
-
- switch ( event->GetType() )
- {
- case CChoreoEvent::FLEXANIMATION:
- {
- if ( pActor )
- {
- DispatchStartFlexAnimation( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::EXPRESSION:
- {
- if ( pActor )
- {
- DispatchStartExpression( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::GESTURE:
- {
- // Verify data.
- Assert( m_bMultiplayer );
- Assert( scene != NULL );
- Assert( event != NULL );
-
- if ( pActor )
- {
- DispatchStartGesture( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::SEQUENCE:
- {
- // Verify data.
- Assert( m_bMultiplayer );
- Assert( scene != NULL );
- Assert( event != NULL );
-
- if ( pActor )
- {
- DispatchStartSequence( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::LOOP:
- {
- // Verify data.
- Assert( m_bMultiplayer );
- Assert( scene != NULL );
- Assert( event != NULL );
-
- DispatchProcessLoop( scene, event );
- }
- case CChoreoEvent::SPEAK:
- {
- if ( IsClientOnly() && pActor )
- {
- // FIXME: dB hack. soundlevel needs to be moved into inside of wav?
- soundlevel_t iSoundlevel = SNDLVL_TALKING;
- if ( event->GetParameters2() )
- {
- iSoundlevel = (soundlevel_t)atoi( event->GetParameters2() );
- if ( iSoundlevel == SNDLVL_NONE )
- {
- iSoundlevel = SNDLVL_TALKING;
- }
- }
-
- DispatchStartSpeak( scene, pActor, event, iSoundlevel );
- }
- }
- break;
- default:
- break;
- }
-
- event->m_flPrevTime = currenttime;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *scene -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event )
-{
- Assert( event->GetType() == CChoreoEvent::LOOP );
-
- float backtime = (float)atof( event->GetParameters() );
-
- bool process = true;
- int counter = event->GetLoopCount();
- if ( counter != -1 )
- {
- int remaining = event->GetNumLoopsRemaining();
- if ( remaining <= 0 )
- {
- process = false;
- }
- else
- {
- event->SetNumLoopsRemaining( --remaining );
- }
- }
-
- if ( !process )
- return;
-
- scene->LoopToTime( backtime );
- SetCurrentTime( backtime, true );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Playback sound file that contains phonemes
-// Input : *actor -
-// *parameters -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel )
-{
- // Emit sound
- if ( IsClientOnly() && actor )
- {
- CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() );
-
- float time_in_past = m_flCurrentTime - event->GetStartTime() ;
- float soundtime = gpGlobals->curtime - time_in_past;
-
- EmitSound_t es;
- es.m_nChannel = CHAN_VOICE;
- es.m_flVolume = 1;
- es.m_SoundLevel = iSoundlevel;
- es.m_flSoundTime = soundtime;
-
- // No CC since we do it manually
- // FIXME: This will change
- es.m_bEmitCloseCaption = false;
- es.m_pSoundName = event->GetParameters();
-
- EmitSound( filter, actor->entindex(), es );
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-
- // Close captioning only on master token no matter what...
- if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
- {
- char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
- bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) );
- if ( validtoken )
- {
- CRC32_t tokenCRC;
- CRC32_Init( &tokenCRC );
-
- char lowercase[ 256 ];
- Q_strncpy( lowercase, tok, sizeof( lowercase ) );
- Q_strlower( lowercase );
-
- CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) );
- CRC32_Final( &tokenCRC );
-
- float endtime = event->GetLastSlaveEndTime();
- float durationShort = event->GetDuration();
- float durationLong = endtime - event->GetStartTime();
- float duration = MAX( durationShort, durationLong );
-
- CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption );
- if ( hudCloseCaption )
- {
- hudCloseCaption->ProcessCaption( lowercase, duration );
- }
- }
-
- }
- }
-}
-
-void C_SceneEntity::DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- if ( IsClientOnly() )
- {
- actor->RemoveSceneEvent( scene, event, false );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : currenttime -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
-{
- Assert( event );
-
- if ( !Q_stricmp( event->GetName(), "NULL" ) )
- {
- return;
- }
-
- C_BaseFlex *pActor = NULL;
- CChoreoActor *actor = event->GetActor();
- if ( actor )
- {
- pActor = FindNamedActor( actor );
- }
-
- Scene_Printf( "%s : %8.2f: finish %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
-
- switch ( event->GetType() )
- {
- case CChoreoEvent::FLEXANIMATION:
- {
- if ( pActor )
- {
- DispatchEndFlexAnimation( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::EXPRESSION:
- {
- if ( pActor )
- {
- DispatchEndExpression( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::GESTURE:
- {
- if ( pActor )
- {
- DispatchEndGesture( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::SEQUENCE:
- {
- if ( pActor )
- {
- DispatchEndSequence( scene, pActor, event );
- }
- }
- break;
- case CChoreoEvent::SPEAK:
- {
- if ( IsClientOnly() && pActor )
- {
- DispatchEndSpeak( scene, pActor, event );
- }
- }
- break;
- default:
- break;
- }
-}
-
-bool CChoreoStringPool::GetString( short stringId, char *buff, int buffSize )
-{
- // fetch from compiled pool
- const char *pString = scenefilecache->GetSceneString( stringId );
- if ( !pString )
- {
- V_strncpy( buff, "", buffSize );
- return false;
- }
- V_strncpy( buff, pString, buffSize );
- return true;
-}
-
-CChoreoStringPool g_ChoreoStringPool;
-
-CChoreoScene *C_SceneEntity::LoadScene( const char *filename )
-{
- char loadfile[ 512 ];
- Q_strncpy( loadfile, filename, sizeof( loadfile ) );
- Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) );
- Q_FixSlashes( loadfile );
-
- char *pBuffer = NULL;
- size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile );
- if ( bufsize <= 0 )
- return NULL;
-
- pBuffer = new char[ bufsize ];
- if ( !scenefilecache->GetSceneData( filename, (byte *)pBuffer, bufsize ) )
- {
- delete[] pBuffer;
- return NULL;
- }
-
- CChoreoScene *pScene;
- if ( IsBufferBinaryVCD( pBuffer, bufsize ) )
- {
- pScene = new CChoreoScene( this );
- CUtlBuffer buf( pBuffer, bufsize, CUtlBuffer::READ_ONLY );
- if ( !pScene->RestoreFromBinaryBuffer( buf, loadfile, &g_ChoreoStringPool ) )
- {
- Warning( "Unable to restore binary scene '%s'\n", loadfile );
- delete pScene;
- pScene = NULL;
- }
- else
- {
- pScene->SetPrintFunc( Scene_Printf );
- pScene->SetEventCallbackInterface( this );
- }
- }
- else
- {
- g_TokenProcessor.SetBuffer( pBuffer );
- pScene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf );
- }
-
- delete[] pBuffer;
- return pScene;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *filename -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::LoadSceneFromFile( const char *filename )
-{
- UnloadScene();
- m_pScene = LoadScene( filename );
-}
-
-void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled )
-{
- if ( !m_pScene )
- return;
-
- Scene_Printf( "%s : %8.2f: clearing events\n", GetSceneFileName(), m_flCurrentTime );
-
- int i;
- for ( i = 0 ; i < m_pScene->GetNumActors(); i++ )
- {
- C_BaseFlex *pActor = FindNamedActor( m_pScene->GetActor( i ) );
- if ( !pActor )
- continue;
-
- // Clear any existing expressions
- pActor->ClearSceneEvents( scene, canceled );
- }
-
- WipeQueuedEvents();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::UnloadScene( void )
-{
- WipeQueuedEvents();
-
- if ( m_pScene )
- {
- ClearSceneEvents( m_pScene, false );
- for ( int i = 0 ; i < m_pScene->GetNumActors(); i++ )
- {
- C_BaseFlex *pTestActor = FindNamedActor( m_pScene->GetActor( i ) );
-
- if ( !pTestActor )
- continue;
-
- pTestActor->RemoveChoreoScene( m_pScene );
- }
- }
- delete m_pScene;
- m_pScene = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- actor->RemoveSceneEvent( scene, event, false );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *event -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- actor->RemoveSceneEvent( scene, event, false );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *parameters -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- // Ingore null gestures
- if ( !Q_stricmp( event->GetName(), "NULL" ) )
- return;
-
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *parameters -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- // Ingore null gestures
- if ( !Q_stricmp( event->GetName(), "NULL" ) )
- return;
-
- actor->RemoveSceneEvent( scene, event, false );
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-// *parameters -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
-{
- // Ingore null gestures
- if ( !Q_stricmp( event->GetName(), "NULL" ) )
- return;
-
- actor->RemoveSceneEvent( scene, event, false );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
-{
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchProcessSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
-{
- actor->RemoveSceneEvent( scene, event, false );
- actor->AddSceneEvent( scene, event, NULL, IsClientOnly() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *actor -
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
-{
- actor->RemoveSceneEvent( scene, event, false );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::DoThink( float frametime )
-{
- if ( !m_pScene )
- return;
-
- if ( !m_bIsPlayingBack )
- {
- WipeQueuedEvents();
- return;
- }
-
- CheckQueuedEvents();
-
- if ( m_bPaused )
- {
- return;
- }
-
- // Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() );
-
- // Tell scene to go
- m_pScene->Think( m_flCurrentTime );
- // Drive simulation time for scene
- m_flCurrentTime += gpGlobals->frametime;
-}
-
-void C_SceneEntity::ClientThink()
-{
- DoThink( gpGlobals->frametime );
-}
-
-void C_SceneEntity::CheckQueuedEvents()
-{
-// Check for duplicates
- CUtlVector< QueuedEvents_t > events;
- events = m_QueuedEvents;
- m_QueuedEvents.RemoveAll();
-
- int c = events.Count();
- for ( int i = 0; i < c; ++i )
- {
- const QueuedEvents_t& check = events[ i ];
-
- // Retry starting this event
- StartEvent( check.starttime, check.scene, check.event );
- }
-}
-
-void C_SceneEntity::WipeQueuedEvents()
-{
- m_QueuedEvents.Purge();
-}
-
-void C_SceneEntity::QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event )
-{
- // Check for duplicates
- int c = m_QueuedEvents.Count();
- for ( int i = 0; i < c; ++i )
- {
- const QueuedEvents_t& check = m_QueuedEvents[ i ];
- if ( check.scene == scene &&
- check.event == event )
- return;
- }
-
- QueuedEvents_t qe;
- qe.scene = scene;
- qe.event = event;
- qe.starttime = starttime;
- m_QueuedEvents.AddToTail( qe );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Resets time such that the client version of the .vcd is also updated, if appropriate
-// Input : t -
-// forceClientSync - unused for now, we may want to reenable this at some point
-//-----------------------------------------------------------------------------
-void C_SceneEntity::SetCurrentTime( float t, bool forceClientSync )
-{
- m_flCurrentTime = t;
- m_flForceClientTime = t;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene )
-{
- if (!CommandLine()->FindParm("-hushasserts"))
- {
- Assert( pScene && m_bMultiplayer );
- }
- if ( !pScene || !m_bMultiplayer )
- return;
-
- // Build a fast lookup, too
- CUtlMap<CChoreoActor*,CBaseFlex*> actorMap( 0, 0, DefLessFunc( CChoreoActor* ) );
-
- int nSpew = 0;
- int nResident = 0;
- int nChecked = 0;
-
- // Iterate events and precache necessary resources
- for ( int i = 0; i < pScene->GetNumEvents(); i++ )
- {
- CChoreoEvent *pEvent = pScene->GetEvent( i );
- if ( !pEvent )
- continue;
-
- // load any necessary data
- switch ( pEvent->GetType() )
- {
- default:
- break;
- case CChoreoEvent::SEQUENCE:
- case CChoreoEvent::GESTURE:
- {
- CChoreoActor *pActor = pEvent->GetActor();
- if ( pActor )
- {
- CBaseFlex *pFlex = NULL;
- int idx = actorMap.Find( pActor );
- if ( idx == actorMap.InvalidIndex() )
- {
- pFlex = FindNamedActor( pActor );
- idx = actorMap.Insert( pActor, pFlex );
- }
- else
- {
- pFlex = actorMap[ idx ];
- }
-
- if ( pFlex )
- {
- int iSequence = pFlex->LookupSequence( pEvent->GetParameters() );
- if ( iSequence >= 0 )
- {
- CStudioHdr *pStudioHdr = pFlex->GetModelPtr();
- if ( pStudioHdr )
- {
- // Now look up the animblock
- mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( iSequence );
- for ( int i = 0 ; i < seqdesc.groupsize[ 0 ] ; ++i )
- {
- for ( int j = 0; j < seqdesc.groupsize[ 1 ]; ++j )
- {
- int iAnimation = seqdesc.anim( i, j );
- int iBaseAnimation = pStudioHdr->iRelativeAnim( iSequence, iAnimation );
- mstudioanimdesc_t &animdesc = pStudioHdr->pAnimdesc( iBaseAnimation );
-
- ++nChecked;
-
- if ( nSpew != 0 )
- {
- Msg( "%s checking block %d\n", pStudioHdr->pszName(), animdesc.animblock );
- }
-
- // Async load the animation
- int iFrame = 0;
- const mstudioanim_t *panim = animdesc.pAnim( &iFrame );
- if ( panim )
- {
- ++nResident;
- if ( nSpew > 1 )
- {
- Msg( "%s:%s[%i:%i] was resident\n", pStudioHdr->pszName(), animdesc.pszName(), i, j );
- }
- }
- else
- {
- if ( nSpew != 0 )
- {
- Msg( "%s:%s[%i:%i] async load\n", pStudioHdr->pszName(), animdesc.pszName(), i, j );
- }
- }
- }
- }
- }
- }
- }
- }
- break;
- }
- }
- }
-
- if ( !nSpew || nChecked <= 0 )
- return;
-
- Msg( "%d of %d animations resident\n", nResident, nChecked );
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "networkstringtable_clientdll.h" +#include "dt_utlvector_recv.h" +#include "choreoevent.h" +#include "choreoactor.h" +#include "choreochannel.h" +#include "filesystem.h" +#include "ichoreoeventcallback.h" +#include "scenefilecache/ISceneFileCache.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "tier2/tier2.h" +#include "hud_closecaption.h" +#include "tier0/icommandline.h" + +#include "c_sceneentity.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Decodes animtime and notes when it changes +// Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine +// *pVarData - +// *pIn - +// objectID - +//----------------------------------------------------------------------------- +void RecvProxy_ForcedClientTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_SceneEntity *pScene = reinterpret_cast< C_SceneEntity * >( pStruct ); + *(float *)pOut = pData->m_Value.m_Float; + pScene->OnResetClientTime(); +} + +#if defined( CSceneEntity ) +#undef CSceneEntity +#endif + +IMPLEMENT_CLIENTCLASS_DT(C_SceneEntity, DT_SceneEntity, CSceneEntity) + RecvPropInt(RECVINFO(m_nSceneStringIndex)), + RecvPropBool(RECVINFO(m_bIsPlayingBack)), + RecvPropBool(RECVINFO(m_bPaused)), + RecvPropBool(RECVINFO(m_bMultiplayer)), + RecvPropFloat(RECVINFO(m_flForceClientTime), 0, RecvProxy_ForcedClientTime ), + RecvPropUtlVector( + RECVINFO_UTLVECTOR( m_hActorList ), + MAX_ACTORS_IN_SCENE, + RecvPropEHandle(NULL, 0, 0)), +END_RECV_TABLE() + +C_SceneEntity::C_SceneEntity( void ) +{ + m_pScene = NULL; + m_bMultiplayer = false; + + m_hOwner = NULL; + m_bClientOnly = false; +} + +C_SceneEntity::~C_SceneEntity( void ) +{ + UnloadScene(); +} + +void C_SceneEntity::OnResetClientTime() +{ + // In TF2 we ignore this as the scene is played entirely client-side. +#ifndef TF_CLIENT_DLL + m_flCurrentTime = m_flForceClientTime; +#endif +} + +char const *C_SceneEntity::GetSceneFileName() +{ + return g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex ); +} + +ConVar mp_usehwmvcds( "mp_usehwmvcds", "0", NULL, "Enable the use of the hw morph vcd(s). (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always +bool UseHWMorphVCDs() +{ +// if ( mp_usehwmvcds.GetInt() == 0 ) +// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures(); +// return mp_usehwmvcds.GetInt() > 0; + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_SceneEntity::GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename ) +{ + // Are we even using hardware morph? + if ( !UseHWMorphVCDs() ) + return false; + + // Multi-player only! + if ( !m_bMultiplayer ) + return false; + + // Do we have a valid filename? + if ( !( pFilename && pFilename[0] ) ) + return false; + + // Check to see if we already have an player/hwm/* filename. + if ( ( V_strstr( pFilename, "/high" ) != NULL ) || ( V_strstr( pFilename, "\\high" ) != NULL ) ) + { + V_strcpy( pHWMFilename, pFilename ); + return true; + } + + // Find the hardware morph scene name and pass that along as well. + char szScene[MAX_PATH]; + V_strcpy( szScene, pFilename ); + + char szSceneHWM[MAX_PATH]; + szSceneHWM[0] = '\0'; + + char *pszToken = strtok( szScene, "/\\" ); + while ( pszToken != NULL ) + { + if ( !V_stricmp( pszToken, "low" ) ) + { + V_strcat( szSceneHWM, "high", sizeof( szSceneHWM ) ); + } + else + { + V_strcat( szSceneHWM, pszToken, sizeof( szSceneHWM ) ); + } + + pszToken = strtok( NULL, "/\\" ); + if ( pszToken != NULL ) + { + V_strcat( szSceneHWM, "\\", sizeof( szSceneHWM ) ); + } + } + + V_strcpy( pHWMFilename, szSceneHWM ); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::ResetActorFlexesForScene() +{ + int nActorCount = m_pScene->GetNumActors(); + for( int iActor = 0; iActor < nActorCount; ++iActor ) + { + CChoreoActor *pChoreoActor = m_pScene->GetActor( iActor ); + if ( !pChoreoActor ) + continue; + + C_BaseFlex *pFlexActor = FindNamedActor( pChoreoActor ); + if ( !pFlexActor ) + continue; + + CStudioHdr *pStudioHdr = pFlexActor->GetModelPtr(); + if ( !pStudioHdr ) + continue; + + if ( pStudioHdr->numflexdesc() == 0 ) + continue; + + // Reset the flex weights to their starting position. + LocalFlexController_t iController; + for ( iController = LocalFlexController_t(0); iController < pStudioHdr->numflexcontrollers(); ++iController ) + { + pFlexActor->SetFlexWeight( iController, 0.0f ); + } + + // Reset the prediction interpolation values. + pFlexActor->m_iv_flexWeight.Reset(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::StopClientOnlyScene() +{ + if ( m_pScene ) + { + m_pScene->ResetSimulation(); + + if ( m_hOwner.Get() ) + { + m_hOwner->RemoveChoreoScene( m_pScene ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner /* = NULL */, bool bMultiplayer /* = false */ ) +{ + m_bIsPlayingBack = true; + m_bMultiplayer = bMultiplayer; + m_hOwner = pOwner; + m_bClientOnly = true; + + char szFilename[128]; + Assert( V_strlen( pszFilename ) < 128 ); + V_strcpy( szFilename, pszFilename ); + + char szSceneHWM[128]; + if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) ) + { + V_strcpy( szFilename, szSceneHWM ); + } + + Assert( szFilename && szFilename[ 0 ] ); + if ( szFilename && szFilename[ 0 ] ) + { + LoadSceneFromFile( szFilename ); + + if (!CommandLine()->FindParm("-hushasserts")) + { + Assert( m_pScene ); + } + + // Should handle gestures and sequences client side. + if ( m_bMultiplayer ) + { + if ( m_pScene ) + { + int types[6]; + types[0] = CChoreoEvent::FLEXANIMATION; + types[1] = CChoreoEvent::EXPRESSION; + types[2] = CChoreoEvent::GESTURE; + types[3] = CChoreoEvent::SEQUENCE; + types[4] = CChoreoEvent::SPEAK; + types[5] = CChoreoEvent::LOOP; + m_pScene->RemoveEventsExceptTypes( types, 6 ); + } + + PrefetchAnimBlocks( m_pScene ); + } + else + { + if ( m_pScene ) + { + int types[ 2 ]; + types[ 0 ] = CChoreoEvent::FLEXANIMATION; + types[ 1 ] = CChoreoEvent::EXPRESSION; + m_pScene->RemoveEventsExceptTypes( types, 2 ); + } + } + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + if ( m_hOwner.Get() ) + { + if (!CommandLine()->FindParm("-hushasserts")) + { + Assert( m_pScene ); + } + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + m_hOwner->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + m_hOwner->RemoveChoreoScene( m_pScene ); + } + + // Reset the flex weights when we start a new scene. This is normally done on the player model, but since + // we don't have a player here yet - we need to do this! + ResetActorFlexesForScene(); + } + } + else + { + for( int i = 0; i < m_hActorList.Count() ; ++i ) + { + C_BaseFlex *actor = m_hActorList[ i ].Get(); + if ( !actor ) + continue; + + Assert( m_pScene ); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + actor->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + actor->RemoveChoreoScene( m_pScene ); + } + } + } + } +} + +void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + char const *str = GetSceneFileName(); + char szFilename[MAX_PATH]; + if ( str ) + { + Assert( V_strlen( str ) < MAX_PATH ); + V_strcpy( szFilename, str ); + } + else + { + szFilename[0] = '\0'; + } + + char szSceneHWM[MAX_PATH]; + if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) ) + { + V_strcpy( szFilename, szSceneHWM ); + } + + if ( updateType == DATA_UPDATE_CREATED ) + { + Assert( szFilename && szFilename[ 0 ] ); + if ( szFilename && szFilename[ 0 ] ) + { + LoadSceneFromFile( szFilename ); + + // Kill everything except flex events + Assert( m_pScene ); + + // Should handle gestures and sequences clientside. + if ( m_bMultiplayer ) + { + if ( m_pScene ) + { + int types[6]; + types[0] = CChoreoEvent::FLEXANIMATION; + types[1] = CChoreoEvent::EXPRESSION; + types[2] = CChoreoEvent::GESTURE; + types[3] = CChoreoEvent::SEQUENCE; + types[4] = CChoreoEvent::SPEAK; + types[5] = CChoreoEvent::LOOP; + m_pScene->RemoveEventsExceptTypes( types, 6 ); + } + + PrefetchAnimBlocks( m_pScene ); + } + else + { + if ( m_pScene ) + { + int types[ 2 ]; + types[ 0 ] = CChoreoEvent::FLEXANIMATION; + types[ 1 ] = CChoreoEvent::EXPRESSION; + m_pScene->RemoveEventsExceptTypes( types, 2 ); + } + } + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + } + + // Playback state changed... + if ( m_bWasPlaying != m_bIsPlayingBack ) + { + for(int i = 0; i < m_hActorList.Count() ; ++i ) + { + C_BaseFlex *actor = m_hActorList[ i ].Get(); + if ( !actor ) + continue; + + Assert( m_pScene ); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + + if ( m_bIsPlayingBack ) + { + m_pScene->ResetSimulation(); + actor->StartChoreoScene( m_pScene ); + } + else + { + m_pScene->ResetSimulation(); + actor->RemoveChoreoScene( m_pScene ); + } + } + } + } +} + +void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PreDataUpdate( updateType ); + + m_bWasPlaying = m_bIsPlayingBack; +} + +//----------------------------------------------------------------------------- +// Purpose: Called every frame that an event is active (Start/EndEvent as also +// called) +// Input : *event - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + // For now we only need to process events if we go back in time. + if ( currenttime < event->m_flPrevTime ) + { + //if ( !V_strstr( scene->GetFilename(), "idleloop" ) ) + //{ + // Msg( "ProcessEvent( %6.4f, %32s %6.4f ) %6.4f\n", currenttime, event->GetName(), event->m_flPrevTime, m_flCurrentTime ); + //} + + C_BaseFlex *pActor = NULL; + CChoreoActor *actor = event->GetActor(); + if ( actor ) + { + pActor = FindNamedActor( actor ); + if ( NULL == pActor ) + { + // TODO: QueueProcessEvent + // This can occur if we haven't been networked an actor yet... we need to queue it so that we can + // fire off the process event as soon as we have the actor resident on the client. + return; + } + } + + switch ( event->GetType() ) + { + case CChoreoEvent::GESTURE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchProcessGesture( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SEQUENCE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchProcessSequence( scene, pActor, event ); + } + } + break; + } + } + + event->m_flPrevTime = currenttime; +} + +//----------------------------------------------------------------------------- +// Purpose: Called for events that are part of a pause condition +// Input : *event - +// Output : Returns true on event completed, false on non-completion. +//----------------------------------------------------------------------------- +bool C_SceneEntity::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + return true; +} + +C_BaseFlex *C_SceneEntity::FindNamedActor( CChoreoActor *pChoreoActor ) +{ + if ( !m_pScene ) + return NULL; + + if ( m_hOwner.Get() != NULL ) + { + return m_hOwner.Get(); + } + + int idx = m_pScene->FindActorIndex( pChoreoActor ); + if ( idx < 0 || idx >= m_hActorList.Count() ) + return NULL; + + return m_hActorList[ idx ].Get(); +} + +//----------------------------------------------------------------------------- +// Purpose: All events are leading edge triggered +// Input : currenttime - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event ); + + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + { + Scene_Printf( "%s : %8.2f: ignored %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + return; + } + + + C_BaseFlex *pActor = NULL; + CChoreoActor *actor = event->GetActor(); + if ( actor ) + { + pActor = FindNamedActor( actor ); + if ( NULL == pActor ) + { + // This can occur if we haven't been networked an actor yet... we need to queue it so that we can + // fire off the start event as soon as we have the actor resident on the client. + QueueStartEvent( currenttime, scene, event ); + return; + } + } + + Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + + switch ( event->GetType() ) + { + case CChoreoEvent::FLEXANIMATION: + { + if ( pActor ) + { + DispatchStartFlexAnimation( scene, pActor, event ); + } + } + break; + case CChoreoEvent::EXPRESSION: + { + if ( pActor ) + { + DispatchStartExpression( scene, pActor, event ); + } + } + break; + case CChoreoEvent::GESTURE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchStartGesture( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SEQUENCE: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + if ( pActor ) + { + DispatchStartSequence( scene, pActor, event ); + } + } + break; + case CChoreoEvent::LOOP: + { + // Verify data. + Assert( m_bMultiplayer ); + Assert( scene != NULL ); + Assert( event != NULL ); + + DispatchProcessLoop( scene, event ); + } + case CChoreoEvent::SPEAK: + { + if ( IsClientOnly() && pActor ) + { + // FIXME: dB hack. soundlevel needs to be moved into inside of wav? + soundlevel_t iSoundlevel = SNDLVL_TALKING; + if ( event->GetParameters2() ) + { + iSoundlevel = (soundlevel_t)atoi( event->GetParameters2() ); + if ( iSoundlevel == SNDLVL_NONE ) + { + iSoundlevel = SNDLVL_TALKING; + } + } + + DispatchStartSpeak( scene, pActor, event, iSoundlevel ); + } + } + break; + default: + break; + } + + event->m_flPrevTime = currenttime; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *scene - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event->GetType() == CChoreoEvent::LOOP ); + + float backtime = (float)atof( event->GetParameters() ); + + bool process = true; + int counter = event->GetLoopCount(); + if ( counter != -1 ) + { + int remaining = event->GetNumLoopsRemaining(); + if ( remaining <= 0 ) + { + process = false; + } + else + { + event->SetNumLoopsRemaining( --remaining ); + } + } + + if ( !process ) + return; + + scene->LoopToTime( backtime ); + SetCurrentTime( backtime, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: Playback sound file that contains phonemes +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel ) +{ + // Emit sound + if ( IsClientOnly() && actor ) + { + CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); + + float time_in_past = m_flCurrentTime - event->GetStartTime() ; + float soundtime = gpGlobals->curtime - time_in_past; + + EmitSound_t es; + es.m_nChannel = CHAN_VOICE; + es.m_flVolume = 1; + es.m_SoundLevel = iSoundlevel; + es.m_flSoundTime = soundtime; + + // No CC since we do it manually + // FIXME: This will change + es.m_bEmitCloseCaption = false; + es.m_pSoundName = event->GetParameters(); + + EmitSound( filter, actor->entindex(), es ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + + // Close captioning only on master token no matter what... + if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) + { + char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ]; + bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ); + if ( validtoken ) + { + CRC32_t tokenCRC; + CRC32_Init( &tokenCRC ); + + char lowercase[ 256 ]; + Q_strncpy( lowercase, tok, sizeof( lowercase ) ); + Q_strlower( lowercase ); + + CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) ); + CRC32_Final( &tokenCRC ); + + float endtime = event->GetLastSlaveEndTime(); + float durationShort = event->GetDuration(); + float durationLong = endtime - event->GetStartTime(); + float duration = MAX( durationShort, durationLong ); + + CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); + if ( hudCloseCaption ) + { + hudCloseCaption->ProcessCaption( lowercase, duration ); + } + } + + } + } +} + +void C_SceneEntity::DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + if ( IsClientOnly() ) + { + actor->RemoveSceneEvent( scene, event, false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : currenttime - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event ); + + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + { + return; + } + + C_BaseFlex *pActor = NULL; + CChoreoActor *actor = event->GetActor(); + if ( actor ) + { + pActor = FindNamedActor( actor ); + } + + Scene_Printf( "%s : %8.2f: finish %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); + + switch ( event->GetType() ) + { + case CChoreoEvent::FLEXANIMATION: + { + if ( pActor ) + { + DispatchEndFlexAnimation( scene, pActor, event ); + } + } + break; + case CChoreoEvent::EXPRESSION: + { + if ( pActor ) + { + DispatchEndExpression( scene, pActor, event ); + } + } + break; + case CChoreoEvent::GESTURE: + { + if ( pActor ) + { + DispatchEndGesture( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SEQUENCE: + { + if ( pActor ) + { + DispatchEndSequence( scene, pActor, event ); + } + } + break; + case CChoreoEvent::SPEAK: + { + if ( IsClientOnly() && pActor ) + { + DispatchEndSpeak( scene, pActor, event ); + } + } + break; + default: + break; + } +} + +bool CChoreoStringPool::GetString( short stringId, char *buff, int buffSize ) +{ + // fetch from compiled pool + const char *pString = scenefilecache->GetSceneString( stringId ); + if ( !pString ) + { + V_strncpy( buff, "", buffSize ); + return false; + } + V_strncpy( buff, pString, buffSize ); + return true; +} + +CChoreoStringPool g_ChoreoStringPool; + +CChoreoScene *C_SceneEntity::LoadScene( const char *filename ) +{ + char loadfile[ 512 ]; + Q_strncpy( loadfile, filename, sizeof( loadfile ) ); + Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) ); + Q_FixSlashes( loadfile ); + + char *pBuffer = NULL; + size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile ); + if ( bufsize <= 0 ) + return NULL; + + pBuffer = new char[ bufsize ]; + if ( !scenefilecache->GetSceneData( filename, (byte *)pBuffer, bufsize ) ) + { + delete[] pBuffer; + return NULL; + } + + CChoreoScene *pScene; + if ( IsBufferBinaryVCD( pBuffer, bufsize ) ) + { + pScene = new CChoreoScene( this ); + CUtlBuffer buf( pBuffer, bufsize, CUtlBuffer::READ_ONLY ); + if ( !pScene->RestoreFromBinaryBuffer( buf, loadfile, &g_ChoreoStringPool ) ) + { + Warning( "Unable to restore binary scene '%s'\n", loadfile ); + delete pScene; + pScene = NULL; + } + else + { + pScene->SetPrintFunc( Scene_Printf ); + pScene->SetEventCallbackInterface( this ); + } + } + else + { + g_TokenProcessor.SetBuffer( pBuffer ); + pScene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf ); + } + + delete[] pBuffer; + return pScene; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *filename - +//----------------------------------------------------------------------------- +void C_SceneEntity::LoadSceneFromFile( const char *filename ) +{ + UnloadScene(); + m_pScene = LoadScene( filename ); +} + +void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled ) +{ + if ( !m_pScene ) + return; + + Scene_Printf( "%s : %8.2f: clearing events\n", GetSceneFileName(), m_flCurrentTime ); + + int i; + for ( i = 0 ; i < m_pScene->GetNumActors(); i++ ) + { + C_BaseFlex *pActor = FindNamedActor( m_pScene->GetActor( i ) ); + if ( !pActor ) + continue; + + // Clear any existing expressions + pActor->ClearSceneEvents( scene, canceled ); + } + + WipeQueuedEvents(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::UnloadScene( void ) +{ + WipeQueuedEvents(); + + if ( m_pScene ) + { + ClearSceneEvents( m_pScene, false ); + for ( int i = 0 ; i < m_pScene->GetNumActors(); i++ ) + { + C_BaseFlex *pTestActor = FindNamedActor( m_pScene->GetActor( i ) ); + + if ( !pTestActor ) + continue; + + pTestActor->RemoveChoreoScene( m_pScene ); + } + } + delete m_pScene; + m_pScene = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *event - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + + actor->RemoveSceneEvent( scene, event, false ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +// *parameters - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) +{ + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +{ + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchProcessSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *actor - +//----------------------------------------------------------------------------- +void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +{ + actor->RemoveSceneEvent( scene, event, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::DoThink( float frametime ) +{ + if ( !m_pScene ) + return; + + if ( !m_bIsPlayingBack ) + { + WipeQueuedEvents(); + return; + } + + CheckQueuedEvents(); + + if ( m_bPaused ) + { + return; + } + + // Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() ); + + // Tell scene to go + m_pScene->Think( m_flCurrentTime ); + // Drive simulation time for scene + m_flCurrentTime += gpGlobals->frametime; +} + +void C_SceneEntity::ClientThink() +{ + DoThink( gpGlobals->frametime ); +} + +void C_SceneEntity::CheckQueuedEvents() +{ +// Check for duplicates + CUtlVector< QueuedEvents_t > events; + events = m_QueuedEvents; + m_QueuedEvents.RemoveAll(); + + int c = events.Count(); + for ( int i = 0; i < c; ++i ) + { + const QueuedEvents_t& check = events[ i ]; + + // Retry starting this event + StartEvent( check.starttime, check.scene, check.event ); + } +} + +void C_SceneEntity::WipeQueuedEvents() +{ + m_QueuedEvents.Purge(); +} + +void C_SceneEntity::QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + // Check for duplicates + int c = m_QueuedEvents.Count(); + for ( int i = 0; i < c; ++i ) + { + const QueuedEvents_t& check = m_QueuedEvents[ i ]; + if ( check.scene == scene && + check.event == event ) + return; + } + + QueuedEvents_t qe; + qe.scene = scene; + qe.event = event; + qe.starttime = starttime; + m_QueuedEvents.AddToTail( qe ); +} + +//----------------------------------------------------------------------------- +// Purpose: Resets time such that the client version of the .vcd is also updated, if appropriate +// Input : t - +// forceClientSync - unused for now, we may want to reenable this at some point +//----------------------------------------------------------------------------- +void C_SceneEntity::SetCurrentTime( float t, bool forceClientSync ) +{ + m_flCurrentTime = t; + m_flForceClientTime = t; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene ) +{ + if (!CommandLine()->FindParm("-hushasserts")) + { + Assert( pScene && m_bMultiplayer ); + } + if ( !pScene || !m_bMultiplayer ) + return; + + // Build a fast lookup, too + CUtlMap<CChoreoActor*,CBaseFlex*> actorMap( 0, 0, DefLessFunc( CChoreoActor* ) ); + + int nSpew = 0; + int nResident = 0; + int nChecked = 0; + + // Iterate events and precache necessary resources + for ( int i = 0; i < pScene->GetNumEvents(); i++ ) + { + CChoreoEvent *pEvent = pScene->GetEvent( i ); + if ( !pEvent ) + continue; + + // load any necessary data + switch ( pEvent->GetType() ) + { + default: + break; + case CChoreoEvent::SEQUENCE: + case CChoreoEvent::GESTURE: + { + CChoreoActor *pActor = pEvent->GetActor(); + if ( pActor ) + { + CBaseFlex *pFlex = NULL; + int idx = actorMap.Find( pActor ); + if ( idx == actorMap.InvalidIndex() ) + { + pFlex = FindNamedActor( pActor ); + idx = actorMap.Insert( pActor, pFlex ); + } + else + { + pFlex = actorMap[ idx ]; + } + + if ( pFlex ) + { + int iSequence = pFlex->LookupSequence( pEvent->GetParameters() ); + if ( iSequence >= 0 ) + { + CStudioHdr *pStudioHdr = pFlex->GetModelPtr(); + if ( pStudioHdr ) + { + // Now look up the animblock + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( iSequence ); + for ( int i = 0 ; i < seqdesc.groupsize[ 0 ] ; ++i ) + { + for ( int j = 0; j < seqdesc.groupsize[ 1 ]; ++j ) + { + int iAnimation = seqdesc.anim( i, j ); + int iBaseAnimation = pStudioHdr->iRelativeAnim( iSequence, iAnimation ); + mstudioanimdesc_t &animdesc = pStudioHdr->pAnimdesc( iBaseAnimation ); + + ++nChecked; + + if ( nSpew != 0 ) + { + Msg( "%s checking block %d\n", pStudioHdr->pszName(), animdesc.animblock ); + } + + // Async load the animation + int iFrame = 0; + const mstudioanim_t *panim = animdesc.pAnim( &iFrame ); + if ( panim ) + { + ++nResident; + if ( nSpew > 1 ) + { + Msg( "%s:%s[%i:%i] was resident\n", pStudioHdr->pszName(), animdesc.pszName(), i, j ); + } + } + else + { + if ( nSpew != 0 ) + { + Msg( "%s:%s[%i:%i] async load\n", pStudioHdr->pszName(), animdesc.pszName(), i, j ); + } + } + } + } + } + } + } + } + break; + } + } + } + + if ( !nSpew || nChecked <= 0 ) + return; + + Msg( "%d of %d animations resident\n", nResident, nChecked ); }
\ No newline at end of file |