//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #if defined(_WIN32) && !defined(_X360) #include #endif #include "basetypes.h" #include #include "choreoscene.h" #include "choreoevent.h" #include "choreochannel.h" #include "choreoactor.h" #include "ichoreoeventcallback.h" #include "iscenetokenprocessor.h" #include "utlbuffer.h" #include "filesystem.h" #include "utlrbtree.h" #include "mathlib/mathlib.h" #include "tier1/strtools.h" #include "tier2/tier2.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #pragma warning( disable : 4127 ) // Let scene linger for 1/4 second so blends can finish #define SCENE_LINGER_TIME 0.25f // The engine turns this to true in dlls/sceneentity.cpp at bool SceneCacheInit()!!! bool CChoreoScene::s_bEditingDisabled = false; //----------------------------------------------------------------------------- // Purpose: Creates scene from a file // Input : *filename - // *pfn - // Output : CChoreoScene //----------------------------------------------------------------------------- CChoreoScene *ChoreoLoadScene( char const *filename, IChoreoEventCallback *callback, ISceneTokenProcessor *tokenizer, void ( *pfn ) ( const char *fmt, ... ) ) { MEM_ALLOC_CREDIT(); CChoreoScene *scene = new CChoreoScene( callback ); Assert( scene ); scene->ParseFromBuffer( filename, tokenizer ); scene->SetPrintFunc( pfn ); return scene; } bool IsBufferBinaryVCD( char *pBuffer, int bufferSize ) { if ( bufferSize > 4 && *(int *)pBuffer == SCENE_BINARY_TAG ) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Debug printout // Input : level - // *fmt - // ... - //----------------------------------------------------------------------------- void CChoreoScene::choreoprintf( int level, const char *fmt, ... ) { char string[ 2048 ]; va_list argptr; va_start( argptr, fmt ); Q_vsnprintf( string, sizeof(string), fmt, argptr ); va_end( argptr ); while ( level-- > 0 ) { if (m_pfnPrint ) { (*m_pfnPrint)( " " ); } else { printf( " " ); } Msg( " " ); } if ( m_pfnPrint ) { (*m_pfnPrint)( string ); } else { printf( "%s", string ); } Msg( "%s", string ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CChoreoScene::CChoreoScene( IChoreoEventCallback *callback ) { Init( callback ); } //----------------------------------------------------------------------------- // Purpose: // Assignment // Input : src - // Output : CChoreoScene& //----------------------------------------------------------------------------- CChoreoScene& CChoreoScene::operator=( const CChoreoScene& src ) { Init( src.m_pIChoreoEventCallback ); // Delete existing int i; for ( i = 0; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; Assert( a ); delete a; } m_Actors.RemoveAll(); for ( i = 0; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; Assert( e ); delete e; } m_Events.RemoveAll(); for ( i = 0 ; i < m_Channels.Count(); i++ ) { CChoreoChannel *c = m_Channels[ i ]; Assert( c ); delete c; } m_Channels.RemoveAll(); m_pTokenizer = src.m_pTokenizer; m_flCurrentTime = src.m_flCurrentTime; m_flStartTime = src.m_flStartTime; m_flEndTime = src.m_flEndTime; m_flSoundSystemLatency = src.m_flSoundSystemLatency; m_pfnPrint = src.m_pfnPrint; m_flLastActiveTime = src.m_flLastActiveTime; m_pTokenizer = src.m_pTokenizer; m_bSubScene = src.m_bSubScene; m_nSceneFPS = src.m_nSceneFPS; m_bUseFrameSnap = src.m_bUseFrameSnap; m_bIgnorePhonemes = src.m_bIgnorePhonemes; // Now copy the object tree // First copy the global events for ( i = 0; i < src.m_Events.Count(); i++ ) { CChoreoEvent *event = src.m_Events[ i ]; if ( event->GetActor() == NULL ) { MEM_ALLOC_CREDIT(); // Copy it CChoreoEvent *newEvent = AllocEvent(); *newEvent = *event; } } // Finally, push actors, channels, events onto global stacks for ( i = 0; i < src.m_Actors.Count(); i++ ) { CChoreoActor *actor = src.m_Actors[ i ]; CChoreoActor *newActor = AllocActor(); *newActor = *actor; for ( int j = 0; j < newActor->GetNumChannels() ; j++ ) { CChoreoChannel *ch = newActor->GetChannel( j ); m_Channels.AddToTail( ch ); for ( int k = 0; k < ch->GetNumEvents(); k++ ) { CChoreoEvent *ev = ch->GetEvent( k ); m_Events.AddToTail( ev ); ev->SetScene( this ); } } } Q_strncpy( m_szMapname, src.m_szMapname, sizeof( m_szMapname ) ); m_SceneRamp = src.m_SceneRamp; m_TimeZoomLookup.RemoveAll(); for ( i = 0; i < (int)src.m_TimeZoomLookup.Count(); i++ ) { m_TimeZoomLookup.Insert( src.m_TimeZoomLookup.GetElementName( i ), src.m_TimeZoomLookup[ i ] ); } Q_strncpy( m_szFileName, src.m_szFileName, sizeof( m_szFileName ) ); m_nLastPauseEvent = src.m_nLastPauseEvent; m_flPrecomputedStopTime = src.m_flPrecomputedStopTime; m_bitvecHasEventOfType = src.m_bitvecHasEventOfType; return *this; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::Init( IChoreoEventCallback *callback ) { m_flPrecomputedStopTime = 0.0f; m_pTokenizer = NULL; m_szMapname[ 0 ] = 0; m_flCurrentTime = 0.0f; m_flStartTime = 0.0f; m_flEndTime = 0.0f; m_flSoundSystemLatency = 0.0f; m_pfnPrint = NULL; m_flLastActiveTime = 0.0f; m_flEarliestTime = 0.0f; m_flLatestTime = 0.0f; m_nActiveEvents = 0; m_pIChoreoEventCallback = callback; m_bSubScene = false; m_nSceneFPS = DEFAULT_SCENE_FPS; m_bUseFrameSnap = false; m_szFileName[0] = 0; m_bIsBackground = false; m_bitvecHasEventOfType.ClearAll(); m_nLastPauseEvent = -1; m_bIgnorePhonemes = false; } //----------------------------------------------------------------------------- // Purpose: Destroy objects and queues //----------------------------------------------------------------------------- CChoreoScene::~CChoreoScene( void ) { int i; for ( i = 0; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; Assert( a ); delete a; } m_Actors.RemoveAll(); for ( i = 0; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; Assert( e ); delete e; } m_Events.RemoveAll(); for ( i = 0 ; i < m_Channels.Count(); i++ ) { CChoreoChannel *c = m_Channels[ i ]; Assert( c ); delete c; } m_Channels.RemoveAll(); } //----------------------------------------------------------------------------- // Ignore phonemes //----------------------------------------------------------------------------- void CChoreoScene::IgnorePhonemes( bool bIgnore ) { m_bIgnorePhonemes = bIgnore; } bool CChoreoScene::ShouldIgnorePhonemes() const { return m_bIgnorePhonemes; } //----------------------------------------------------------------------------- // Purpose: // Input : *callback - //----------------------------------------------------------------------------- void CChoreoScene::SetEventCallbackInterface( IChoreoEventCallback *callback ) { m_pIChoreoEventCallback = callback; } //----------------------------------------------------------------------------- // Purpose: // Input : level - // *e - //----------------------------------------------------------------------------- void CChoreoScene::PrintEvent( int level, CChoreoEvent *e ) { choreoprintf( level, "event %s \"%s\"\n", CChoreoEvent::NameForType( e->GetType() ), e->GetName() ); choreoprintf( level, "{\n" ); choreoprintf( level + 1, "time %f %f\n", e->GetStartTime(), e->GetEndTime() ); choreoprintf( level + 1, "param \"%s\"\n", e->GetParameters() ); if ( strlen( e->GetParameters2() ) > 0 ) { choreoprintf( level + 1, "param2 \"%s\"\n", e->GetParameters2() ); } if ( strlen( e->GetParameters3() ) > 0 ) { choreoprintf( level + 1, "param3 \"%s\"\n", e->GetParameters3() ); } choreoprintf( level, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : level - // *c - //----------------------------------------------------------------------------- void CChoreoScene::PrintChannel( int level, CChoreoChannel *c ) { choreoprintf( level, "channel \"%s\"\n", c->GetName() ); choreoprintf( level, "{\n" ); for ( int i = 0; i < c->GetNumEvents(); i++ ) { CChoreoEvent *e = c->GetEvent( i ); if ( e ) { PrintEvent( level + 1, e ); } } choreoprintf( level, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : level - // *a - //----------------------------------------------------------------------------- void CChoreoScene::PrintActor( int level, CChoreoActor *a ) { choreoprintf( level, "actor \"%s\"\n", a->GetName() ); choreoprintf( level, "{\n" ); for ( int i = 0; i < a->GetNumChannels(); i++ ) { CChoreoChannel *c = a->GetChannel( i ); if ( c ) { PrintChannel( level + 1, c ); } } choreoprintf( level, "}\n\n" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::Print( void ) { // Look for events that don't have actor/channel set int i; for ( i = 0 ; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetActor() ) continue; PrintEvent( 0, e ); } for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; PrintActor( 0, a ); } } //----------------------------------------------------------------------------- // Purpose: prints if m_pfnPrint is active // Output : //----------------------------------------------------------------------------- void CChoreoScene::SceneMsg( const char *pFormat, ... ) { char string[ 2048 ]; va_list argptr; va_start( argptr, pFormat ); Q_vsnprintf( string, sizeof(string), pFormat, argptr ); va_end( argptr ); if ( m_pfnPrint ) { (*m_pfnPrint)( string ); } else { Msg( "%s", string ); } } //----------------------------------------------------------------------------- // Purpose: // Output : CChoreoEvent //----------------------------------------------------------------------------- CChoreoEvent *CChoreoScene::AllocEvent( void ) { MEM_ALLOC_CREDIT_CLASS(); CChoreoEvent *e = new CChoreoEvent( this ); Assert( e ); m_Events.AddToTail( e ); return e; } //----------------------------------------------------------------------------- // Purpose: // Output : CChoreoChannel //----------------------------------------------------------------------------- CChoreoChannel *CChoreoScene::AllocChannel( void ) { MEM_ALLOC_CREDIT_CLASS(); CChoreoChannel *c = new CChoreoChannel(); Assert( c ); m_Channels.AddToTail( c ); return c; } //----------------------------------------------------------------------------- // Purpose: // Output : CChoreoActor //----------------------------------------------------------------------------- CChoreoActor *CChoreoScene::AllocActor( void ) { MEM_ALLOC_CREDIT_CLASS(); CChoreoActor *a = new CChoreoActor; Assert( a ); m_Actors.AddToTail( a ); return a; } //----------------------------------------------------------------------------- // Purpose: // Input : *name - // Output : CChoreoActor //----------------------------------------------------------------------------- CChoreoActor *CChoreoScene::FindActor( const char *name ) { for ( int i = 0; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; if ( !Q_stricmp( a->GetName(), name ) ) return a; } return NULL; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CChoreoScene::GetNumEvents( void ) { return m_Events.Count(); } //----------------------------------------------------------------------------- // Purpose: // Input : event - // Output : CChoreoEvent //----------------------------------------------------------------------------- CChoreoEvent *CChoreoScene::GetEvent( int event ) { if ( event < 0 || event >= m_Events.Count() ) return NULL; return m_Events[ event ]; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CChoreoScene::GetNumActors( void ) { return m_Actors.Count(); } //----------------------------------------------------------------------------- // Purpose: // Input : actor - // Output : CChoreoActor //----------------------------------------------------------------------------- CChoreoActor *CChoreoScene::GetActor( int actor ) { if ( actor < 0 || actor >= GetNumActors() ) return NULL; return m_Actors[ actor ]; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CChoreoScene::GetNumChannels( void ) { return m_Channels.Count(); } //----------------------------------------------------------------------------- // Purpose: // Input : channel - // Output : CChoreoChannel //----------------------------------------------------------------------------- CChoreoChannel *CChoreoScene::GetChannel( int channel ) { if ( channel < 0 || channel >= GetNumChannels() ) return NULL; return m_Channels[ channel ]; } void CChoreoScene::ParseRamp( ISceneTokenProcessor *tokenizer, CChoreoEvent *e ) { e->GetRamp()->Parse( tokenizer, e ); } void CChoreoScene::ParseSceneRamp( ISceneTokenProcessor *tokenizer, CChoreoScene *scene ) { scene->m_SceneRamp.Parse( tokenizer, scene ); } void CCurveData::Parse( ISceneTokenProcessor *tokenizer, ICurveDataAccessor *data ) { Clear(); tokenizer->GetToken( true ); if ( !Q_stricmp( tokenizer->CurrentToken(), "leftedge" ) ) { CChoreoScene::ParseEdgeInfo( tokenizer, &m_RampEdgeInfo[ 0 ] ); } if ( !Q_stricmp( tokenizer->CurrentToken(), "rightedge" ) ) { CChoreoScene::ParseEdgeInfo( tokenizer, &m_RampEdgeInfo[ 1 ] ); } if ( stricmp( tokenizer->CurrentToken(), "{" ) ) tokenizer->Error( "expecting {\n" ); while ( 1 ) { // Parse until } tokenizer->GetToken( true ); if ( strlen( tokenizer->CurrentToken() ) <= 0 ) { tokenizer->Error( "expecting ramp data\n" ); break; } if ( !Q_stricmp( tokenizer->CurrentToken(), "}" ) ) break; CUtlVector< CExpressionSample > samples; float time = (float)atof( tokenizer->CurrentToken() ); tokenizer->GetToken( false ); float value = (float)atof( tokenizer->CurrentToken() ); // Add to counter int idx = samples.AddToTail(); CExpressionSample *s = &samples[ idx ]; s->time = time; s->value = value; // If there are more tokens on this line, then it's a new format curve name if ( tokenizer->TokenAvailable() ) { tokenizer->GetToken( false ); int curveType = Interpolator_CurveTypeForName( tokenizer->CurrentToken() ); s->SetCurveType( curveType ); } if ( samples.Count() >= 1 ) { for ( int i = 0; i < samples.Count(); i++ ) { CExpressionSample sample = samples[ i ]; CExpressionSample *newSample = Add( sample.time, sample.value, false ); newSample->SetCurveType( sample.GetCurveType() ); } } } Resort( data ); } //----------------------------------------------------------------------------- // Purpose: Helper for restoring edge info // Input : *edgeinfo - //----------------------------------------------------------------------------- void CChoreoScene::ParseEdgeInfo( ISceneTokenProcessor *tokenizer, EdgeInfo_t *edgeinfo ) { Assert( edgeinfo ); Assert( tokenizer ); tokenizer->GetToken( false ); edgeinfo->m_bActive = true; edgeinfo->m_CurveType = Interpolator_CurveTypeForName( tokenizer->CurrentToken() ); tokenizer->GetToken( false ); edgeinfo->m_flZeroPos = atof( tokenizer->CurrentToken() ); tokenizer->GetToken( true ); } //----------------------------------------------------------------------------- // Purpose: // Input : *tokenizer - // *e - //----------------------------------------------------------------------------- void CChoreoScene::ParseFlexAnimations( ISceneTokenProcessor *tokenizer, CChoreoEvent *e, bool removeold /*= true*/ ) { Assert( e ); if ( removeold ) { // Make sure there's nothing already there... e->RemoveAllTracks(); // Make it re-index e->SetTrackLookupSet( false ); } // BACKWARD COMPATABILITY // in the old system the samples were 0.0 to 1.0 mapped to endtime - starttime // if samples_use_time is true, then samples are actually offsets of time from starttime bool samples_use_realtime = false; // Parse tags between { } // tokenizer->GetToken( true ); Assert( e->HasEndTime() ); float endtime = e->GetEndTime(); float starttime = e->GetStartTime(); float event_time = endtime - starttime; int nDefaultCurveType = CURVE_DEFAULT; // Is it the new file format? if ( !Q_stricmp( tokenizer->CurrentToken(), "samples_use_time" ) ) { samples_use_realtime = true; tokenizer->GetToken( true ); } // Check for default curve type if ( !Q_strnicmp( tokenizer->CurrentToken(), "defaultcurvetype", 16 ) ) { const char *pTest = tokenizer->CurrentToken() + 16; if ( *pTest == 0 ) { tokenizer->GetToken( true ); pTest = tokenizer->CurrentToken(); } if ( *pTest != '=' ) { tokenizer->Error( "expecting =\n" ); } ++pTest; if ( *pTest == 0 ) { tokenizer->GetToken( true ); pTest = tokenizer->CurrentToken(); } nDefaultCurveType = Interpolator_CurveTypeForName( pTest ); tokenizer->GetToken( true ); e->SetDefaultCurveType( nDefaultCurveType ); } if ( stricmp( tokenizer->CurrentToken(), "{" ) ) { tokenizer->Error( "expecting {\n" ); } while ( 1 ) { // Parse until } tokenizer->GetToken( true ); if ( strlen( tokenizer->CurrentToken() ) <= 0 ) { tokenizer->Error( "expecting flex animation data\n" ); break; } if ( !Q_stricmp( tokenizer->CurrentToken(), "}" ) ) break; char flexcontroller[ CFlexAnimationTrack::MAX_CONTROLLER_NAME ]; Q_strncpy( flexcontroller, tokenizer->CurrentToken(), sizeof( flexcontroller ) ); // Animations default to active bool active = true; bool combo = false; float range_min = 0.0f; float range_max = 1.0f; tokenizer->GetToken( true ); EdgeInfo_t edgeinfo[ 2 ]; if ( !Q_stricmp( tokenizer->CurrentToken(), "disabled" ) ) { active = false; tokenizer->GetToken( true ); } if ( !Q_stricmp( tokenizer->CurrentToken(), "combo" ) ) { combo = true; tokenizer->GetToken( true ); } if ( !Q_stricmp( tokenizer->CurrentToken(), "range" ) ) { tokenizer->GetToken( false ); range_min = atof( tokenizer->CurrentToken() ); tokenizer->GetToken( false ); range_max = atof( tokenizer->CurrentToken() ); tokenizer->GetToken( true ); } if ( !Q_stricmp( tokenizer->CurrentToken(), "leftedge" ) ) { ParseEdgeInfo( tokenizer, &edgeinfo[ 0 ] ); } if ( !Q_stricmp( tokenizer->CurrentToken(), "rightedge" ) ) { ParseEdgeInfo( tokenizer, &edgeinfo[ 1 ] ); } CUtlVector< CExpressionSample > samples[2]; for ( int samplecount = 0; samplecount < ( combo ? 2 : 1 ); samplecount++ ) { if ( stricmp( tokenizer->CurrentToken(), "{" ) ) { tokenizer->Error( "expecting {\n" ); } while ( 1 ) { tokenizer->GetToken( true ); if ( strlen( tokenizer->CurrentToken() ) <= 0 ) { tokenizer->Error( "expecting flex animation data\n" ); break; } if ( !Q_stricmp( tokenizer->CurrentToken(), "}" ) ) break; float time = (float)atof( tokenizer->CurrentToken() ); tokenizer->GetToken( false ); float value = (float)atof( tokenizer->CurrentToken() ); // Add to counter int idx = samples[ samplecount ].AddToTail(); CExpressionSample *s = &samples[ samplecount ][ idx ]; if ( samples_use_realtime ) { s->time = time; } else { // Time is an old style fraction (0 to 1) map into real time s->time = time * event_time; } s->value = value; // If there are more tokens on this line, then it's a new format curve name if ( tokenizer->TokenAvailable() ) { tokenizer->GetToken( false ); int curveType = Interpolator_CurveTypeForName( tokenizer->CurrentToken() ); s->SetCurveType( curveType ); } else { s->SetCurveType( nDefaultCurveType ); } } if ( combo && samplecount == 0 ) { tokenizer->GetToken( true ); } } if ( active || samples[ 0 ].Count() >= 1 ) { // Add it in CFlexAnimationTrack *track = e->AddTrack( flexcontroller ); Assert( track ); track->SetTrackActive( active ); track->SetComboType( combo ); track->SetMin( range_min ); track->SetMax( range_max ); for ( int t = 0; t < ( combo ? 2 : 1 ); t++ ) { for ( int i = 0; i < samples[ t ].Count(); i++ ) { CExpressionSample *sample = &samples[ t ][ i ]; CExpressionSample *added = track->AddSample( sample->time, sample->value, t ); Assert( added ); added->SetCurveType( sample->GetCurveType() ); } } for ( int edge = 0; edge < 2; ++edge ) { if ( !edgeinfo[ edge ].m_bActive ) continue; track->SetEdgeActive( edge == 0 ? true : false, true ); track->SetEdgeInfo( edge == 0 ? true : false, edgeinfo[ edge ].m_CurveType, edgeinfo[ edge ].m_flZeroPos ); } track->Resort( 0 ); track->Resort( 1 ); } } } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - // *channel - // Output : CChoreoEvent //----------------------------------------------------------------------------- CChoreoEvent *CChoreoScene::ParseEvent( CChoreoActor *actor, CChoreoChannel *channel ) { // For conversion of old style attack/sustain/decay ramps bool hadramp = false; float attack = 1.0f, sustain = 1.0f, decay = 1.0f; CChoreoEvent *e; { MEM_ALLOC_CREDIT(); e = AllocEvent(); } MEM_ALLOC_CREDIT(); Assert( e ); // read event type m_pTokenizer->GetToken( false ); e->SetType( CChoreoEvent::TypeForName( m_pTokenizer->CurrentToken() ) ); m_pTokenizer->GetToken( false ); e->SetName( m_pTokenizer->CurrentToken() ); m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {\n" ); while ( 1 ) { m_pTokenizer->GetToken( true ); if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) { m_pTokenizer->Error( "expecting more tokens!" ); break; } if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "time" ) ) { float start, end = 1.0f; m_pTokenizer->GetToken( false ); start = (float)atof( m_pTokenizer->CurrentToken() ); if ( m_pTokenizer->TokenAvailable() ) { m_pTokenizer->GetToken( false ); end = (float)atof( m_pTokenizer->CurrentToken() ); } e->SetStartTime( start ); e->SetEndTime( end ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "ramp" ) ) { hadramp = true; m_pTokenizer->GetToken( false ); attack = (float)atof( m_pTokenizer->CurrentToken() ); if ( m_pTokenizer->TokenAvailable() ) { m_pTokenizer->GetToken( false ); sustain = (float)atof( m_pTokenizer->CurrentToken() ); } if ( m_pTokenizer->TokenAvailable() ) { m_pTokenizer->GetToken( false ); decay = (float)atof( m_pTokenizer->CurrentToken() ); } } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "param" ) ) { m_pTokenizer->GetToken( false ); e->SetParameters( m_pTokenizer->CurrentToken() ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "param2" ) ) { m_pTokenizer->GetToken( false ); e->SetParameters2( m_pTokenizer->CurrentToken() ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "param3" ) ) { m_pTokenizer->GetToken( false ); e->SetParameters3( m_pTokenizer->CurrentToken() ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "pitch" ) ) { m_pTokenizer->GetToken( false ); e->SetPitch( atoi( m_pTokenizer->CurrentToken() ) ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "yaw" ) ) { m_pTokenizer->GetToken( false ); e->SetYaw( atoi( m_pTokenizer->CurrentToken() ) ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "loopcount" ) ) { m_pTokenizer->GetToken( false ); e->SetLoopCount( atoi( m_pTokenizer->CurrentToken() ) ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "resumecondition" ) ) { e->SetResumeCondition( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "fixedlength" ) ) { e->SetFixedLength( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "lockbodyfacing" ) ) { e->SetLockBodyFacing( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "distancetotarget" ) ) { m_pTokenizer->GetToken( false ); e->SetDistanceToTarget( atof( m_pTokenizer->CurrentToken() ) ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "forceshortmovement" ) ) { e->SetForceShortMovement( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "synctofollowinggesture" ) ) { e->SetSyncToFollowingGesture( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "active" ) ) { m_pTokenizer->GetToken( false ); e->SetActive( atoi( m_pTokenizer->CurrentToken() ) ? true : false ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "playoverscript" ) ) { e->SetPlayOverScript( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "tags" ) ) { // Parse tags between { } // m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {\n" ); while ( 1 ) { // Parse until } m_pTokenizer->GetToken( true ); if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) { m_pTokenizer->Error( "expecting relative tag\n" ); break; } if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; char tagname[ CEventRelativeTag::MAX_EVENTTAG_LENGTH ]; float percentage; Q_strncpy( tagname, m_pTokenizer->CurrentToken(), sizeof( tagname ) ); m_pTokenizer->GetToken( false ); percentage = (float)atof( m_pTokenizer->CurrentToken() ); e->AddRelativeTag( tagname, percentage ); } } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "sequenceduration" ) ) { float duration = 0.0f; m_pTokenizer->GetToken( false ); duration = (float)atof( m_pTokenizer->CurrentToken() ); e->SetGestureSequenceDuration( duration ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "absolutetags" ) ) { m_pTokenizer->GetToken( true ); CChoreoEvent::AbsTagType tagtype; tagtype = CChoreoEvent::TypeForAbsoluteTagName( m_pTokenizer->CurrentToken() ); if ( tagtype == (CChoreoEvent::AbsTagType) -1 ) { m_pTokenizer->Error( "expecting valid tag type!!!" ); } // Parse tags between { } // m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {\n" ); while ( 1 ) { // Parse until } m_pTokenizer->GetToken( true ); if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) { m_pTokenizer->Error( "expecting relative tag\n" ); break; } if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; char tagname[ CFlexTimingTag::MAX_EVENTTAG_LENGTH ]; float t; Q_strncpy( tagname, m_pTokenizer->CurrentToken(), sizeof( tagname ) ); m_pTokenizer->GetToken( false ); t = (float)atof( m_pTokenizer->CurrentToken() ); e->AddAbsoluteTag( tagtype, tagname, t ); } } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "flextimingtags" ) ) { // Parse tags between { } // m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {\n" ); while ( 1 ) { // Parse until } m_pTokenizer->GetToken( true ); if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) { m_pTokenizer->Error( "expecting relative tag\n" ); break; } if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; char tagname[ CFlexTimingTag::MAX_EVENTTAG_LENGTH ]; float percentage; bool locked; Q_strncpy( tagname, m_pTokenizer->CurrentToken(), sizeof( tagname ) ); m_pTokenizer->GetToken( false ); percentage = (float)atof( m_pTokenizer->CurrentToken() ); m_pTokenizer->GetToken( false ); locked = atoi( m_pTokenizer->CurrentToken() ) ? true : false; e->AddTimingTag( tagname, percentage, locked ); } } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "relativetag" ) ) { char tagname[ CChoreoEvent::MAX_TAGNAME_STRING ]; char wavname[ CChoreoEvent::MAX_TAGNAME_STRING ]; m_pTokenizer->GetToken( false ); Q_strncpy( tagname, m_pTokenizer->CurrentToken(), sizeof( tagname ) ); m_pTokenizer->GetToken( false ); Q_strncpy( wavname, m_pTokenizer->CurrentToken(), sizeof( wavname ) ); e->SetUsingRelativeTag( true, tagname, wavname ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "flexanimations" ) ) { ParseFlexAnimations( m_pTokenizer, e ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "event_ramp" ) ) { ParseRamp( m_pTokenizer, e ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "cctype" ) ) { m_pTokenizer->GetToken( false ); e->SetCloseCaptionType( CChoreoEvent::CCTypeForName( m_pTokenizer->CurrentToken() ) ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "cctoken" ) ) { m_pTokenizer->GetToken( false ); e->SetCloseCaptionToken( m_pTokenizer->CurrentToken() ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "cc_usingcombinedfile" ) ) { e->SetUsingCombinedFile( true ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "cc_combinedusesgender" ) ) { e->SetCombinedUsingGenderToken( true ); } else if( !Q_stricmp( m_pTokenizer->CurrentToken(), "cc_noattenuate" ) ) { e->SetSuppressingCaptionAttenuation( true ); } } if ( channel ) { channel->AddEvent( e ); } e->SetActor( actor ); e->SetChannel( channel ); // It had old sytle ramp and none of the new style stuff // Convert it if ( hadramp && !e->GetRampCount() ) { // Only retrofit if something was changed by user if ( attack != 1.0f || sustain != 1.0f || decay != 1.0f ) { float attacktime = ( 1.0f - attack ) * e->GetDuration(); float decaytime = decay * e->GetDuration(); float midpoint = ( attacktime + decaytime ) * 0.5f; e->AddRamp( attacktime, sustain, false ); e->AddRamp( midpoint, sustain, false ); e->AddRamp( decaytime, sustain, false ); e->ResortRamp(); } } return e; } //----------------------------------------------------------------------------- // Purpose: // Output : CChoreoActor //----------------------------------------------------------------------------- CChoreoActor *CChoreoScene::ParseActor( void ) { CChoreoActor *a = AllocActor(); Assert( a ); m_pTokenizer->GetToken( false ); a->SetName( m_pTokenizer->CurrentToken() ); m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {" ); // Parse channels while ( 1 ) { m_pTokenizer->GetToken( true ); if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "channel" ) ) { ParseChannel( a ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "faceposermodel" ) ) { ParseFacePoserModel( a ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "active" ) ) { m_pTokenizer->GetToken( true ); a->SetActive( atoi( m_pTokenizer->CurrentToken() ) ? true : false ); } else { m_pTokenizer->Error( "expecting channel got %s\n", m_pTokenizer->CurrentToken() ); } } return a; } //----------------------------------------------------------------------------- // Output : char const //----------------------------------------------------------------------------- const char *CChoreoScene::GetMapname( void ) { return m_szMapname; } //----------------------------------------------------------------------------- // Purpose: // Input : *name - //----------------------------------------------------------------------------- void CChoreoScene::SetMapname( const char *name ) { Q_strncpy( m_szMapname, name, sizeof( m_szMapname ) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ParseMapname( void ) { m_szMapname[ 0 ] = 0; m_pTokenizer->GetToken( true ); Q_strncpy( m_szMapname, m_pTokenizer->CurrentToken(), sizeof( m_szMapname ) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ParseFPS( void ) { m_pTokenizer->GetToken( true ); m_nSceneFPS = atoi( m_pTokenizer->CurrentToken() ); // Clamp to valid range m_nSceneFPS = clamp( m_nSceneFPS, MIN_SCENE_FPS, MAX_SCENE_FPS); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ParseSnap( void ) { m_pTokenizer->GetToken( true ); m_bUseFrameSnap = !Q_stricmp( m_pTokenizer->CurrentToken(), "on" ) ? true : false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ParseIgnorePhonemes( void ) { m_pTokenizer->GetToken( true ); m_bIgnorePhonemes = !Q_stricmp( m_pTokenizer->CurrentToken(), "on" ) ? true : false; } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - //----------------------------------------------------------------------------- void CChoreoScene::ParseFacePoserModel( CChoreoActor *actor ) { m_pTokenizer->GetToken( true ); actor->SetFacePoserModelName( m_pTokenizer->CurrentToken() ); } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - // Output : CChoreoChannel //----------------------------------------------------------------------------- CChoreoChannel *CChoreoScene::ParseChannel( CChoreoActor *actor ) { CChoreoChannel *c = AllocChannel(); Assert( c ); m_pTokenizer->GetToken( false ); c->SetName( m_pTokenizer->CurrentToken() ); m_pTokenizer->GetToken( true ); if ( stricmp( m_pTokenizer->CurrentToken(), "{" ) ) m_pTokenizer->Error( "expecting {" ); // Parse channels while ( 1 ) { m_pTokenizer->GetToken( true ); if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "}" ) ) break; if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "event" ) ) { ParseEvent( actor, c ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "active" ) ) { m_pTokenizer->GetToken( true ); c->SetActive( atoi( m_pTokenizer->CurrentToken() ) ? true : false ); } else { m_pTokenizer->Error( "expecting event got %s\n", m_pTokenizer->CurrentToken() ); } } Assert( actor ); if ( actor ) { actor->AddChannel( c ); c->SetActor( actor ); } return c; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CChoreoScene::ParseFromBuffer( const char *pFilename, ISceneTokenProcessor *tokenizer ) { Q_strncpy( m_szFileName, pFilename, sizeof(m_szFileName) ); m_pTokenizer = tokenizer; while ( 1 ) { if ( !m_pTokenizer->GetToken( true ) ) { break; } if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) break; if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "event" ) ) { ParseEvent( NULL, NULL ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "actor" ) ) { ParseActor(); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "mapname" ) ) { ParseMapname(); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "fps" ) ) { ParseFPS(); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "snap" ) ) { ParseSnap(); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "ignorePhonemes" ) ) { ParseIgnorePhonemes(); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "scene_ramp" ) ) { ParseSceneRamp( m_pTokenizer, this ); } else if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "scalesettings" ) ) { ParseScaleSettings( m_pTokenizer, this ); } else { m_pTokenizer->Error( "%s: unexpected token %s\n", m_szFileName, m_pTokenizer->CurrentToken() ); break; } } // Fixup time tags ReconcileTags(); ReconcileGestureTimes(); ReconcileCloseCaption(); InternalDetermineEventTypes(); if ( CChoreoScene::s_bEditingDisabled ) { m_flPrecomputedStopTime = FindStopTime(); } return true; } void CChoreoScene::RemoveEventsExceptTypes( int* typeList, int count ) { int i; for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; int num = c->GetNumEvents(); for ( int k = num - 1 ; k >= 0; --k ) { CChoreoEvent *e = c->GetEvent( k ); if ( !e ) continue; bool found = false; for ( int idx = 0; idx < count; ++idx ) { if ( e->GetType() == ( CChoreoEvent::EVENTTYPE )typeList[ idx ] ) { found = true; break; } } if ( !found ) { c->RemoveEvent( e ); DeleteReferencedObjects( e ); } } } } // Remvoe non-matching global events, too for ( i = m_Events.Count() - 1 ; i >= 0; --i ) { CChoreoEvent *e = m_Events[ i ]; // This was already dealt with above... if ( e->GetActor() ) continue; bool found = false; for ( int idx = 0; idx < count; ++idx ) { if ( e->GetType() == ( CChoreoEvent::EVENTTYPE )typeList[ idx ] ) { found = true; break; } } if ( !found ) { DeleteReferencedObjects( e ); } } } void CChoreoScene::InternalDetermineEventTypes() { m_bitvecHasEventOfType.ClearAll(); for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; for ( int k = 0 ; k < c->GetNumEvents(); k++ ) { CChoreoEvent *e = c->GetEvent( k ); if ( !e ) continue; m_bitvecHasEventOfType.Set( e->GetType(), true ); } } } } //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CChoreoScene::FindStopTime( void ) { if ( m_flPrecomputedStopTime != 0.0f ) { return m_flPrecomputedStopTime; } float lasttime = 0.0f; int c = m_Events.Count(); for ( int i = 0; i < c ; i++ ) { CChoreoEvent *e = m_Events[ i ]; Assert( e ); float checktime = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime(); if ( checktime > lasttime ) { lasttime = checktime; } } return lasttime; } float CChoreoScene::FindLastSpeakTime( void ) const { // walk backward from the end of events to the beginning looking for the last speak event const int c = m_Events.Count(); int lastSpeakEvent; for ( lastSpeakEvent = c-1 ; lastSpeakEvent >= 0 ; --lastSpeakEvent ) { CChoreoEvent * RESTRICT e = m_Events[ lastSpeakEvent ]; Assert( e ); if ( e->GetType() == CChoreoEvent::SPEAK ) break; } if ( lastSpeakEvent < 0 ) // we found no speak event { return 0; } /* // now walk forward from the beginning to the last event counting the duration of each event float lasttime = 0.0f; for ( int i = 0; i <= lastSpeakEvent ; i++ ) { CChoreoEvent * RESTRICT e = m_Events[ i ]; Assert( e ); float checktime = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime(); if ( checktime > lasttime ) { lasttime = checktime; } } return lasttime; */ CChoreoEvent * RESTRICT finalSpeechEvent = m_Events[lastSpeakEvent]; return finalSpeechEvent->HasEndTime() ? finalSpeechEvent->GetEndTime() : finalSpeechEvent->GetStartTime(); } //----------------------------------------------------------------------------- // Purpose: // Input : *fp - // level - // *fmt - // ... - //----------------------------------------------------------------------------- void CChoreoScene::FilePrintf( CUtlBuffer& buf, int level, const char *fmt, ... ) { va_list argptr; va_start( argptr, fmt ); while ( level-- > 0 ) { buf.Printf( " " ); } buf.VaPrintf( fmt, argptr ); va_end( argptr ); } //----------------------------------------------------------------------------- // Purpose: // Input : *fp - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveHeader( CUtlBuffer& buf ) { FilePrintf( buf, 0, "// Choreo version 1\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : mark - //----------------------------------------------------------------------------- void CChoreoScene::MarkForSaveAll( bool mark ) { int i; // Mark global events for ( i = 0 ; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetActor() ) continue; e->SetMarkedForSave( mark ); } // Recursively mark everything else for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; a->MarkForSaveAll( mark ); } } //----------------------------------------------------------------------------- // Purpose: // Input : *filename - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CChoreoScene::ExportMarkedToFile( const char *filename ) { // Create a serialization buffer CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); FileSaveHeader( buf ); // Look for events that don't have actor/channel set int i; for ( i = 0 ; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetActor() ) continue; FileSaveEvent( buf, 0, e ); } for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; FileSaveActor( buf, 0, a ); } // Write it out baby FileHandle_t fh = g_pFullFileSystem->Open( filename, "wt" ); if (fh) { g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh ); g_pFullFileSystem->Close(fh); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: // Input : *filename - //----------------------------------------------------------------------------- bool CChoreoScene::SaveToFile( const char *filename ) { // Create a serialization buffer CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); FileSaveHeader( buf ); MarkForSaveAll( true ); // Look for events that don't have actor/channel set int i; for ( i = 0 ; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetActor() ) continue; FileSaveEvent( buf, 0, e ); } for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; FileSaveActor( buf, 0, a ); } if ( m_szMapname[ 0 ] ) { FilePrintf( buf, 0, "mapname \"%s\"\n", m_szMapname ); } FileSaveSceneRamp( buf, 0 ); FileSaveScaleSettings( buf, 0, this ); FilePrintf( buf, 0, "fps %i\n", m_nSceneFPS ); FilePrintf( buf, 0, "snap %s\n", m_bUseFrameSnap ? "on" : "off" ); FilePrintf( buf, 0, "ignorePhonemes %s\n", m_bIgnorePhonemes ? "on" : "off" ); // Write it out baby FileHandle_t fh = g_pFullFileSystem->Open( filename, "wt" ); if (fh) { g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh ); g_pFullFileSystem->Close(fh); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // level - // *e - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveRamp( CUtlBuffer& buf, int level, CChoreoEvent *e ) { e->GetRamp()->FileSave( buf, level, "event_ramp" ); } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // level - // *e - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveSceneRamp( CUtlBuffer& buf, int level ) { m_SceneRamp.FileSave( buf, level, "scene_ramp" ); } void CCurveData::FileSave( CUtlBuffer& buf, int level, const char *name ) { // Nothing to save? int c = GetCount(); if ( c <= 0 && !IsEdgeActive( true ) && !IsEdgeActive( false ) ) return; char line[ 1024 ]; Q_strncpy( line, name, sizeof( line ) ); if ( IsEdgeActive( true ) || IsEdgeActive( false ) ) { if ( IsEdgeActive( true ) ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), " leftedge %s %.3f", Interpolator_NameForCurveType( GetEdgeCurveType( true ), false ), GetEdgeZeroValue( true ) ); Q_strncat( line, sz, sizeof( line ), COPY_ALL_CHARACTERS ); } if ( IsEdgeActive( false ) ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz )," rightedge %s %.3f", Interpolator_NameForCurveType( GetEdgeCurveType( false ), false ), GetEdgeZeroValue( false ) ); Q_strncat( line, sz, sizeof( line ), COPY_ALL_CHARACTERS ); } } CChoreoScene::FilePrintf( buf, level, "%s\n", line ); CChoreoScene::FilePrintf( buf, level, "{\n" ); for ( int i = 0; i < c; i++ ) { CExpressionSample *sample = Get( i ); if ( sample->GetCurveType() != CURVE_DEFAULT ) { CChoreoScene::FilePrintf( buf, level + 1, "%.4f %.4f \"%s\"\n", sample->time, sample->value, Interpolator_NameForCurveType( sample->GetCurveType(), false ) ); } else { CChoreoScene::FilePrintf( buf, level + 1, "%.4f %.4f\n", sample->time, sample->value ); } } CChoreoScene::FilePrintf( buf, level, "}\n" ); } void CChoreoScene::FileSaveScaleSettings( CUtlBuffer& buf, int level, CChoreoScene *scene ) { // Nothing to save? int c = scene->m_TimeZoomLookup.Count(); if ( c <= 0 ) return; FilePrintf( buf, level, "scalesettings\n" ); FilePrintf( buf, level, "{\n" ); for ( int i = 0; i < c; i++ ) { int value = scene->m_TimeZoomLookup[ i ]; FilePrintf( buf, level + 1, "\"%s\" \"%i\"\n", scene->m_TimeZoomLookup.GetElementName( i ), value ); } FilePrintf( buf, level, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // level - // *track - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveFlexAnimationTrack( CUtlBuffer& buf, int level, CFlexAnimationTrack *track, int nDefaultCurveType ) { if ( !track ) return; if ( !track->IsTrackActive() && track->GetNumSamples() <= 0 ) return; char line[ 1024 ]; Q_snprintf( line, sizeof( line ), "\"%s\" ", track->GetFlexControllerName() ); if ( !track->IsTrackActive() ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), "disabled " ); Q_strncat( line, sz, sizeof( line ), COPY_ALL_CHARACTERS ); } if ( track->IsComboType() ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), "combo " ); Q_strncat( line, sz, sizeof( line ), COPY_ALL_CHARACTERS ); } if ( track->GetMin() != 0.0f || track->GetMax() != 1.0f) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), "range %.1f %.1f ", track->GetMin(), track->GetMax() ); Q_strncat( line, sz, sizeof( line ), COPY_ALL_CHARACTERS ); } if ( track->IsEdgeActive( true ) || track->IsEdgeActive( false ) ) { char edgestr[ 512 ]; edgestr[ 0 ] = 0; if ( track->IsEdgeActive( true ) ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), "leftedge %s %.3f ", Interpolator_NameForCurveType( track->GetEdgeCurveType( true ), false ), track->GetEdgeZeroValue( true ) ); Q_strncat( edgestr, sz, sizeof( edgestr ), COPY_ALL_CHARACTERS ); } if ( track->IsEdgeActive( false ) ) { char sz[ 256 ]; Q_snprintf( sz, sizeof( sz ), "rightedge %s %.3f ", Interpolator_NameForCurveType( track->GetEdgeCurveType( false ), false ), track->GetEdgeZeroValue( false ) ); Q_strncat( edgestr, sz, sizeof( edgestr ), COPY_ALL_CHARACTERS ); } Q_strncat( line, edgestr, sizeof( line ), COPY_ALL_CHARACTERS ); } FilePrintf( buf, level + 2, "%s\n", line ); // Write out samples FilePrintf( buf, level + 2, "{\n" ); for ( int j = 0 ; j < track->GetNumSamples( 0 ) ; j++ ) { CExpressionSample *s = track->GetSample( j, 0 ); if ( !s ) continue; if ( s->GetCurveType() != nDefaultCurveType && s->GetCurveType() != CURVE_DEFAULT ) { FilePrintf( buf, level + 3, "%.4f %.4f \"%s\"\n", s->time, s->value, Interpolator_NameForCurveType( s->GetCurveType(), false ) ); } else { FilePrintf( buf, level + 3, "%.4f %.4f\n", s->time, s->value ); } } FilePrintf( buf, level + 2, "}\n" ); // Write out combo samples if ( track->IsComboType() ) { FilePrintf( buf, level + 2, "{\n" ); for ( int j = 0 ; j < track->GetNumSamples( 1) ; j++ ) { CExpressionSample *s = track->GetSample( j, 1 ); if ( !s ) continue; if ( s->GetCurveType() != nDefaultCurveType && s->GetCurveType() != CURVE_DEFAULT ) { FilePrintf( buf, level + 3, "%.4f %.4f \"%s\"\n", s->time, s->value, Interpolator_NameForCurveType( s->GetCurveType(), false ) ); } else { FilePrintf( buf, level + 3, "%.4f %.4f\n", s->time, s->value ); } } FilePrintf( buf, level + 2, "}\n" ); } } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // level - // *e - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveFlexAnimations( CUtlBuffer& buf, int level, CChoreoEvent *e ) { // Nothing to save if ( e->GetNumFlexAnimationTracks() <= 0 ) return; if ( e->GetDefaultCurveType() != CURVE_DEFAULT ) { FilePrintf( buf, level + 1, "flexanimations samples_use_time defaultcurvetype=%s\n", Interpolator_NameForCurveType( e->GetDefaultCurveType(), false ) ); } else { FilePrintf( buf, level + 1, "flexanimations samples_use_time\n" ); } FilePrintf( buf, level + 1, "{\n" ); for ( int i = 0; i < e->GetNumFlexAnimationTracks(); i++ ) { CFlexAnimationTrack *track = e->GetFlexAnimationTrack( i ); FileSaveFlexAnimationTrack( buf, level, track, e->GetDefaultCurveType() ); } FilePrintf( buf, level + 1, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : *fp - // level - // *e - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveEvent( CUtlBuffer& buf, int level, CChoreoEvent *e ) { if ( !e->IsMarkedForSave() ) return; FilePrintf( buf, level, "event %s \"%s\"\n", CChoreoEvent::NameForType( e->GetType() ), e->GetName() ); FilePrintf( buf, level, "{\n" ); float st, et; st = e->GetStartTime(); et = e->GetEndTime(); FilePrintf( buf, level + 1, "time %f %f\n", st, et ); FilePrintf( buf, level + 1, "param \"%s\"\n", e->GetParameters() ); if ( strlen( e->GetParameters2() ) > 0 ) { FilePrintf( buf, level + 1, "param2 \"%s\"\n", e->GetParameters2() ); } if ( strlen( e->GetParameters3() ) > 0 ) { FilePrintf( buf, level + 1, "param3 \"%s\"\n", e->GetParameters3() ); } if ( e->GetRampCount() > 0 ) { FileSaveRamp( buf, level + 1, e ); } if ( e->GetPitch() != 0 ) { FilePrintf( buf, level + 1, "pitch \"%i\"\n", e->GetPitch() ); } if ( e->GetYaw() != 0 ) { FilePrintf( buf, level + 1, "yaw \"%i\"\n", e->GetYaw() ); } if ( e->IsResumeCondition() ) { FilePrintf( buf, level + 1, "resumecondition\n" ); } if ( e->IsLockBodyFacing() ) { FilePrintf( buf, level + 1, "lockbodyfacing\n" ); } if ( e->GetDistanceToTarget() > 0.0f ) { FilePrintf( buf, level + 1, "distancetotarget %.2f\n", e->GetDistanceToTarget() ); } if ( e->GetForceShortMovement() ) { FilePrintf( buf, level + 1, "forceshortmovement\n" ); } if ( e->GetSyncToFollowingGesture() ) { FilePrintf( buf, level + 1, "synctofollowinggesture\n" ); } if ( !e->GetActive() ) { FilePrintf( buf, level + 1, "active 0\n" ); } if ( e->GetPlayOverScript() ) { FilePrintf( buf, level + 1, "playoverscript\n" ); } if ( e->IsFixedLength() ) { FilePrintf( buf, level + 1, "fixedlength\n" ); } if ( e->GetNumRelativeTags() > 0 ) { FilePrintf( buf, level + 1, "tags\n" ); FilePrintf( buf, level + 1, "{\n" ); for ( int t = 0; t < e->GetNumRelativeTags(); t++ ) { CEventRelativeTag *rt = e->GetRelativeTag( t ); Assert( rt ); FilePrintf( buf, level + 2, "\"%s\" %f\n", rt->GetName(), rt->GetPercentage() ); } FilePrintf( buf, level + 1, "}\n" ); } if ( e->GetNumTimingTags() > 0 ) { FilePrintf( buf, level + 1, "flextimingtags\n" ); FilePrintf( buf, level + 1, "{\n" ); for ( int t = 0; t < e->GetNumTimingTags(); t++ ) { CFlexTimingTag *tt = e->GetTimingTag( t ); Assert( tt ); FilePrintf( buf, level + 2, "\"%s\" %f %i\n", tt->GetName(), tt->GetPercentage(), tt->GetLocked() ? 1 : 0 ); } FilePrintf( buf, level + 1, "}\n" ); } int tagtype; for ( tagtype = 0; tagtype < CChoreoEvent::NUM_ABS_TAG_TYPES; tagtype++ ) { if ( e->GetNumAbsoluteTags( (CChoreoEvent::AbsTagType)tagtype ) > 0 ) { FilePrintf( buf, level + 1, "absolutetags %s\n", CChoreoEvent::NameForAbsoluteTagType( (CChoreoEvent::AbsTagType)tagtype ) ); FilePrintf( buf, level + 1, "{\n" ); for ( int t = 0; t < e->GetNumAbsoluteTags( (CChoreoEvent::AbsTagType)tagtype ); t++ ) { CEventAbsoluteTag *abstag = e->GetAbsoluteTag( (CChoreoEvent::AbsTagType)tagtype, t ); Assert( abstag ); FilePrintf( buf, level + 2, "\"%s\" %f\n", abstag->GetName(), abstag->GetPercentage() ); } FilePrintf( buf, level + 1, "}\n" ); } } if ( e->GetType() == CChoreoEvent::GESTURE ) { float duration; if ( e->GetGestureSequenceDuration( duration ) ) { FilePrintf( buf, level + 1, "sequenceduration %f\n", duration ); } } if ( e->IsUsingRelativeTag() ) { FilePrintf( buf, level + 1, "relativetag \"%s\" \"%s\"\n", e->GetRelativeTagName(), e->GetRelativeWavName() ); } if ( e->GetNumFlexAnimationTracks() > 0 ) { FileSaveFlexAnimations( buf, level, e ); } if ( e->GetType() == CChoreoEvent::LOOP ) { FilePrintf( buf, level + 1, "loopcount \"%i\"\n", e->GetLoopCount() ); } if ( e->GetType() == CChoreoEvent::SPEAK ) { FilePrintf( buf, level + 1, "cctype \"%s\"\n", CChoreoEvent::NameForCCType( e->GetCloseCaptionType() ) ); FilePrintf( buf, level + 1, "cctoken \"%s\"\n", e->GetCloseCaptionToken() ); if ( e->GetCloseCaptionType() != CChoreoEvent::CC_DISABLED && e->IsUsingCombinedFile() ) { FilePrintf( buf, level + 1, "cc_usingcombinedfile\n" ); } if ( e->IsCombinedUsingGenderToken() ) { FilePrintf( buf, level + 1, "cc_combinedusesgender\n" ); } if ( e->IsSuppressingCaptionAttenuation() ) { FilePrintf( buf, level + 1, "cc_noattenuate\n" ); } } FilePrintf( buf, level, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : *fp - // level - // *c - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveChannel( CUtlBuffer& buf, int level, CChoreoChannel *c ) { if ( !c->IsMarkedForSave() ) return; FilePrintf( buf, level, "channel \"%s\"\n", c->GetName() ); FilePrintf( buf, level, "{\n" ); for ( int i = 0; i < c->GetNumEvents(); i++ ) { CChoreoEvent *e = c->GetEvent( i ); if ( e ) { FileSaveEvent( buf, level + 1, e ); } } if ( !c->GetActive() ) { // Only write out inactive FilePrintf( buf, level + 1, "active \"0\"\n" ); } FilePrintf( buf, level, "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : *fp - // level - // *a - //----------------------------------------------------------------------------- void CChoreoScene::FileSaveActor( CUtlBuffer& buf, int level, CChoreoActor *a ) { if ( !a->IsMarkedForSave() ) return; FilePrintf( buf, level, "actor \"%s\"\n", a->GetName() ); FilePrintf( buf, level, "{\n" ); for ( int i = 0; i < a->GetNumChannels(); i++ ) { CChoreoChannel *c = a->GetChannel( i ); if ( c ) { FileSaveChannel( buf, level + 1, c ); } } if ( Q_strlen( a->GetFacePoserModelName() ) > 0 ) { FilePrintf( buf, level + 1, "faceposermodel \"%s\"\n", a->GetFacePoserModelName() ); } if ( !a->GetActive() ) { // Only write out inactive FilePrintf( buf, level + 1, "active \"0\"\n" ); } FilePrintf( buf, level, "}\n\n" ); } //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CChoreoScene::FindAdjustedStartTime( void ) { float earliest_time = 0.0f; CChoreoEvent *e; for ( int i = 0; i < m_Events.Count(); i++ ) { e = m_Events[ i ]; float starttime = e->GetStartTime(); // If it's a wav file, pre-queue the starting time by the sound system's // current latency if ( e->GetType() == CChoreoEvent::SPEAK ) { starttime -= m_flSoundSystemLatency; } if ( starttime < earliest_time ) { earliest_time = starttime; } } return earliest_time; } //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CChoreoScene::FindAdjustedEndTime( void ) { float latest_time = 0.0f; CChoreoEvent *e; for ( int i = 0; i < m_Events.Count(); i++ ) { e = m_Events[ i ]; float endtime = e->GetStartTime(); if ( e->HasEndTime() ) { endtime = e->GetEndTime(); } // If it's a wav file, pre-queue the starting time by the sound system's // current latency if ( e->GetType() == CChoreoEvent::SPEAK ) { endtime += m_flSoundSystemLatency; } if ( endtime > latest_time ) { latest_time = endtime; } } return latest_time; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ResetSimulation( bool forward /*= true*/, float starttime /*= 0.0f*/, float endtime /*= 0.0f*/ ) { CChoreoEvent *e; m_ActiveResumeConditions.RemoveAll(); m_ResumeConditions.RemoveAll(); m_PauseEvents.RemoveAll(); // Put all items into the pending queue for ( int i = 0; i < m_Events.Count(); i++ ) { e = m_Events[ i ]; e->ResetProcessing(); if ( e->GetType() == CChoreoEvent::SECTION ) { m_PauseEvents.AddToTail( e ); continue; } if ( e->IsResumeCondition() ) { m_ResumeConditions.AddToTail( e ); continue; } } // Find earliest adjusted start time m_flEarliestTime = FindAdjustedStartTime(); m_flLatestTime = FindAdjustedEndTime(); m_flCurrentTime = forward ? m_flEarliestTime : m_flLatestTime; // choreoprintf( 0, "Start time %f\n", m_flCurrentTime ); m_flLastActiveTime = 0.0f; m_nActiveEvents = m_Events.Count(); m_flStartTime = starttime; m_flEndTime = endtime; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CChoreoScene::CheckEventCompletion( void ) { CChoreoEvent *e; bool bAllCompleted = true; // check all items in the active pending queue for ( int i = 0; i < m_ActiveResumeConditions.Count(); i++ ) { e = m_ActiveResumeConditions[ i ]; bAllCompleted = bAllCompleted && e->CheckProcessing( m_pIChoreoEventCallback, this, m_flCurrentTime ); } return bAllCompleted; } //----------------------------------------------------------------------------- // Returns true if the last speech event in the scene has triggered, // even if other scene events are still running or pending. //----------------------------------------------------------------------------- bool CChoreoScene::SpeechFinished( void ) const { // look through all the events and find the latest end time // for a speech event. (They aren't necessarily stored in order.) float lastEndTime = -1; const int c = m_Events.Count(); for ( int i = 0 ; i < c ; ++i ) { if ( m_Events[i]->GetType() == CChoreoEvent::SPEAK ) { float endtime = m_Events[i]->GetEndTime(); lastEndTime = MAX( lastEndTime, endtime ); } } if ( lastEndTime >= 0 ) { return m_flCurrentTime >= lastEndTime; } else { return false; } } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CChoreoScene::SimulationFinished( void ) { // Scenes linger for a little bit to allow things to settle // check for events that are still active... if ( m_flCurrentTime > m_flLatestTime ) { if ( m_nActiveEvents != 0 ) { return false; } return true; } if ( m_flCurrentTime < m_flEarliestTime ) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CChoreoEvent *CChoreoScene::FindPauseBetweenTimes( float starttime, float endtime ) { CChoreoEvent *e; // Iterate through all events in the scene for ( int i = 0; i < m_PauseEvents.Count(); i++ ) { e = m_PauseEvents[ i ]; if ( !e ) continue; Assert( e->GetType() == CChoreoEvent::SECTION ); int time_is = IsTimeInRange( e->GetStartTime(), starttime, endtime ); if ( IN_RANGE != time_is ) continue; // Found a pause in between start and end time return e; } // No pause inside the specified time span return NULL; } int CChoreoScene::IsTimeInRange( float t, float starttime, float endtime ) { if ( t > endtime ) { return AFTER_RANGE; } else if ( t < starttime ) { return BEFORE_RANGE; } return IN_RANGE; } int CChoreoScene::EventThink( CChoreoEvent *e, float frame_start_time, float frame_end_time, bool playing_forward, PROCESSING_TYPE& disposition ) { disposition = PROCESSING_TYPE_IGNORE; int iret = 0; bool hasend = e->HasEndTime(); float starttime, endtime; starttime = e->GetStartTime(); endtime = hasend ? e->GetEndTime() : e->GetStartTime(); if ( !playing_forward ) { // Swap intervals float temp = frame_start_time; frame_start_time = frame_end_time; frame_end_time = temp; } bool suppressed = false; // Special processing switch ( e->GetType() ) { default: break; case CChoreoEvent::SPEAK: // If it's a wav file, pre-queue the starting/endtime time by the sound system's // current latency { if ( playing_forward ) { starttime -= m_flSoundSystemLatency; // Search for pause condition in between the original time and the // adjusted start time, but make sure that the pause event hasn't already triggered... CChoreoEvent *pauseEvent = FindPauseBetweenTimes( starttime, starttime + m_flSoundSystemLatency ); if ( pauseEvent && ( frame_start_time <= pauseEvent->GetStartTime() ) ) { pauseEvent->AddEventDependency( e ); suppressed = true; } } /* else // Don't bother if playing backward!!! { endtime += m_flSoundSystemLatency; // Search for pause condition in between the original time and the // adjusted start time CChoreoEvent *pauseEvent = FindPauseBetweenTimes( endtime - m_flSoundSystemLatency, endtime ); if ( pauseEvent ) { pauseEvent->AddEventDependency( e ); suppressed = true; } } */ } break; case CChoreoEvent::SUBSCENE: { if ( IsSubScene() ) { suppressed = true; } } break; } if ( suppressed ) { if ( e->IsProcessing() ) { disposition = PROCESSING_TYPE_STOP; } return iret; } int where_is_event; if ( e->IsProcessing() ) { where_is_event = IsTimeInRange( frame_start_time, starttime, endtime ); if ( IN_RANGE == where_is_event ) { disposition = PROCESSING_TYPE_CONTINUE; iret = 1; } else { disposition = PROCESSING_TYPE_STOP; } } else { // Is the event supposed to be active at this time where_is_event = IsTimeInRange( frame_start_time, starttime, endtime ); if ( IN_RANGE == where_is_event ) { if ( e->IsResumeCondition() ) { disposition = PROCESSING_TYPE_START_RESUMECONDITION; } else { disposition = PROCESSING_TYPE_START; } iret = 1; } // See if it's a single fire event which should occur during this frame else if ( !hasend ) { where_is_event = IsTimeInRange( starttime, frame_start_time, frame_end_time ); if ( IN_RANGE == where_is_event ) { disposition = PROCESSING_TYPE_START; iret = 1; } } } return iret; } //----------------------------------------------------------------------------- // Purpose: // Input : &e0 - // &e1 - // Output : static bool //----------------------------------------------------------------------------- bool CChoreoScene::EventLess( const CChoreoScene::ActiveList &al0, const CChoreoScene::ActiveList &al1 ) { CChoreoEvent *event0, *event1; event0 = const_cast< CChoreoEvent * >( al0.e ); event1 = const_cast< CChoreoEvent * >( al1.e ); if ( event0->GetStartTime() < event1->GetStartTime() ) { return true; } if ( event0->GetStartTime() > event1->GetStartTime() ) { return false; } // Check for end time overlap if ( event0->HasEndTime() && event1->HasEndTime() ) { if ( event0->GetEndTime() > event1->GetEndTime() ) return true; else if ( event0->GetEndTime() < event1->GetEndTime() ) return false; } CChoreoActor *a0, *a1; a0 = event0->GetActor(); a1 = event1->GetActor(); // Start time equal, go to order in channel if ( !a0 || !a1 || a0 != a1 ) { return strcmp( event0->GetName(), event1->GetName() ) == -1; } CChoreoChannel *c0 = event0->GetChannel(); CChoreoChannel *c1 = event1->GetChannel(); if ( !c0 || !c1 || c0 != c1 ) { return strcmp( event0->GetName(), event1->GetName() ) == -1; } // Go by slot within channel int index0 = a0->FindChannelIndex( c0 ); int index1 = a1->FindChannelIndex( c1 ); return ( index0 < index1 ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ClearPauseEventDependencies() { int c = m_PauseEvents.Count(); for ( int i = 0 ; i < c; ++i ) { CChoreoEvent *pause = m_PauseEvents[ i ]; Assert( pause ); pause->ClearEventDependencies(); } } //----------------------------------------------------------------------------- // Purpose: // Input : *pauseEvent - // *suppressed - //----------------------------------------------------------------------------- void CChoreoScene::AddPauseEventDependency( CChoreoEvent *pauseEvent, CChoreoEvent *suppressed ) { Assert( pauseEvent ); Assert( pauseEvent != suppressed ); pauseEvent->AddEventDependency( suppressed ); } //----------------------------------------------------------------------------- // Purpose: // Input : dt - //----------------------------------------------------------------------------- void CChoreoScene::Think( float curtime ) { CChoreoEvent *e; float oldt = m_flCurrentTime; float dt = curtime - oldt; bool playing_forward = ( dt >= 0.0f ) ? true : false; m_nActiveEvents = 0; ClearPauseEventDependencies(); CUtlRBTree< ActiveList, int > pending(0,0,EventLess); // Iterate through all events in the scene int i; for ( i = 0; i < m_Events.Count(); i++ ) { e = m_Events[ i ]; if ( !e ) continue; PROCESSING_TYPE disposition; m_nActiveEvents += EventThink( e, m_flCurrentTime, curtime, playing_forward, disposition ); if ( disposition != PROCESSING_TYPE_IGNORE ) { ActiveList entry; entry.e = e; entry.pt = disposition; pending.Insert( entry ); } } // Events are sorted start time and then by channel and actor slot or by name if those aren't equal bool dump = false; i = pending.FirstInorder(); while ( i != pending.InvalidIndex() ) { ActiveList *entry = &pending[ i ]; Assert( entry->e ); if ( dump ) { Msg( "%f == %s starting at %f (actor %p channel %p)\n", m_flCurrentTime, entry->e->GetName(), entry->e->GetStartTime(), entry->e->GetActor(), entry->e->GetChannel() ); } switch ( entry->pt ) { default: case PROCESSING_TYPE_IGNORE: { Assert( 0 ); } break; case PROCESSING_TYPE_START: case PROCESSING_TYPE_START_RESUMECONDITION: { entry->e->StartProcessing( m_pIChoreoEventCallback, this, m_flCurrentTime ); if ( entry->pt == PROCESSING_TYPE_START_RESUMECONDITION ) { Assert( entry->e->IsResumeCondition() ); m_ActiveResumeConditions.AddToTail( entry->e ); } // This event can "pause" the scene, so we need to remember who "paused" the scene so that // when we resume we can resume any suppressed events dependent on this pauser... if ( entry->e->GetType() == CChoreoEvent::SECTION ) { // So this event should be in the pauseevents list, otherwise this'll be -1 m_nLastPauseEvent = m_PauseEvents.Find( entry->e ); } } break; case PROCESSING_TYPE_CONTINUE: { entry->e->ContinueProcessing( m_pIChoreoEventCallback, this, m_flCurrentTime ); } break; case PROCESSING_TYPE_STOP: { entry->e->StopProcessing( m_pIChoreoEventCallback, this, m_flCurrentTime ); } break; } i = pending.NextInorder( i ); } if ( dump ) { Msg( "\n" ); } // If a Process call slams this time, don't override it!!! if ( oldt == m_flCurrentTime ) { m_flCurrentTime = curtime; } // Still processing? if ( m_nActiveEvents ) { m_flLastActiveTime = m_flCurrentTime; } } //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CChoreoScene::GetTime( void ) { return m_flCurrentTime; } //----------------------------------------------------------------------------- // Purpose: // Input : t - //----------------------------------------------------------------------------- void CChoreoScene::SetTime( float t ) { m_flCurrentTime = t; } //----------------------------------------------------------------------------- // Purpose: // Input : t - //----------------------------------------------------------------------------- void CChoreoScene::LoopToTime( float t ) { m_flCurrentTime = t; } //----------------------------------------------------------------------------- // Purpose: // Input : *pfn - //----------------------------------------------------------------------------- void CChoreoScene::SetPrintFunc( void ( *pfn ) ( const char *fmt, ... ) ) { m_pfnPrint = pfn; } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - //----------------------------------------------------------------------------- void CChoreoScene::RemoveActor( CChoreoActor *actor ) { int idx = FindActorIndex( actor ); if ( idx == -1 ) return; m_Actors.Remove( idx ); } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - // Output : int //----------------------------------------------------------------------------- int CChoreoScene::FindActorIndex( CChoreoActor *actor ) { for ( int i = 0; i < m_Actors.Count(); i++ ) { if ( actor == m_Actors[ i ] ) { return i; } } return -1; } //----------------------------------------------------------------------------- // Purpose: // Input : a1 - // a2 - //----------------------------------------------------------------------------- void CChoreoScene::SwapActors( int a1, int a2 ) { CChoreoActor *temp; temp = m_Actors[ a1 ]; m_Actors[ a1 ] = m_Actors[ a2 ]; m_Actors[ a2 ] = temp; } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - //----------------------------------------------------------------------------- void CChoreoScene::DeleteReferencedObjects( CChoreoActor *actor ) { for ( int i = 0; i < actor->GetNumChannels(); i++ ) { CChoreoChannel *channel = actor->GetChannel( i ); actor->RemoveChannel( channel ); DeleteReferencedObjects( channel ); } DestroyActor( actor ); } //----------------------------------------------------------------------------- // Purpose: // Input : *channel - //----------------------------------------------------------------------------- void CChoreoScene::DeleteReferencedObjects( CChoreoChannel *channel ) { for ( int i = 0; i < channel->GetNumEvents(); i++ ) { CChoreoEvent *event = channel->GetEvent( i ); channel->RemoveEvent( event ); DeleteReferencedObjects( event ); } DestroyChannel( channel ); } //----------------------------------------------------------------------------- // Purpose: // Input : *event - //----------------------------------------------------------------------------- void CChoreoScene::DeleteReferencedObjects( CChoreoEvent *event ) { int idx = m_PauseEvents.Find( event ); if ( idx != m_PauseEvents.InvalidIndex() ) { m_PauseEvents.Remove( idx ); } // Events don't reference anything lower DestroyEvent( event ); } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - //----------------------------------------------------------------------------- void CChoreoScene::DestroyActor( CChoreoActor *actor ) { int size = m_Actors.Count(); for ( int i = size - 1; i >= 0; i-- ) { CChoreoActor *a = m_Actors[ i ]; if ( a == actor ) { m_Actors.Remove( i ); } } delete actor; } //----------------------------------------------------------------------------- // Purpose: // Input : *channel - //----------------------------------------------------------------------------- void CChoreoScene::DestroyChannel( CChoreoChannel *channel ) { int size = m_Channels.Count(); for ( int i = size - 1; i >= 0; i-- ) { CChoreoChannel *c = m_Channels[ i ]; if ( c == channel ) { m_Channels.Remove( i ); } } delete channel; } //----------------------------------------------------------------------------- // Purpose: // Input : *event - //----------------------------------------------------------------------------- void CChoreoScene::DestroyEvent( CChoreoEvent *event ) { int size = m_Events.Count(); for ( int i = size - 1; i >= 0; i-- ) { CChoreoEvent *e = m_Events[ i ]; if ( e == event ) { m_Events.Remove( i ); } } delete event; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ResumeSimulation( void ) { // If the thing that paused us was a SECTION pause event, then this will be set if ( m_nLastPauseEvent >= 0 && m_nLastPauseEvent < m_PauseEvents.Count() ) { // Start any suppressed dependencies immediately, should only be .wav files!!! // These are .wav files which are placed at or just after the SECTION pause event // in the .vcd, but due to the user's sound system latency, they would have triggered before the // pause (we pre-queue sounds). Since we suppressed that, we need to unsupress / start these sounds // now that the SECTION pause is being resumed from CUtlVector< CChoreoEvent * > deps; CChoreoEvent *pauseEvent = m_PauseEvents[ m_nLastPauseEvent ]; Assert( pauseEvent ); // Sanity check ( this should be about 1 tick usually 15 msec) float timeSincePaused = m_flCurrentTime - pauseEvent->GetStartTime(); if ( fabs( timeSincePaused ) > 1.0f ) { Assert( !"Resume simulation with unexpected pause event" ); } // Snag any sounds which were suppressed by this issue pauseEvent->GetEventDependencies( deps ); for ( int j = 0; j < deps.Count(); ++j ) { CChoreoEvent *startEvent = deps[ j ]; Assert( startEvent ); // Start them now. Yes, they won't pre-queue, but it's better than totally skipping the sound!!! startEvent->StartProcessing( m_pIChoreoEventCallback, this, m_flCurrentTime ); } } // Reset section pause signal m_nLastPauseEvent = -1; m_ActiveResumeConditions.RemoveAll(); } // Sound system needs to have sounds pre-queued by this much time void CChoreoScene::SetSoundFileStartupLatency( float time ) { Assert( time >= 0 ); m_flSoundSystemLatency = time; } //----------------------------------------------------------------------------- // Purpose: // Input : start - // end - //----------------------------------------------------------------------------- void CChoreoScene::GetSceneTimes( float& start, float& end ) { start = m_flStartTime; end = m_flEndTime; } //----------------------------------------------------------------------------- // Purpose: Do housekeeping on times that are relative to tags //----------------------------------------------------------------------------- void CChoreoScene::ReconcileTags( void ) { for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; for ( int k = 0 ; k < c->GetNumEvents(); k++ ) { CChoreoEvent *e = c->GetEvent( k ); if ( !e ) continue; if ( !e->IsUsingRelativeTag() ) continue; CEventRelativeTag *tag = FindTagByName( e->GetRelativeWavName(), e->GetRelativeTagName() ); if ( tag ) { // Determine correct starting time based on tag float starttime = tag->GetStartTime(); // Figure out delta float dt = starttime - e->GetStartTime(); // Fix up start and possible end time e->OffsetTime( dt ); } else { // The tag was missing!!! unflag it choreoprintf( 0, "Event %s was missing tag %s for wav %s\n", e->GetName(), e->GetRelativeWavName(), e->GetRelativeTagName() ); e->SetUsingRelativeTag( false, "", "" ); } } } } } //----------------------------------------------------------------------------- // Purpose: // Input : *wavname - // *name - // Output : CChoreoEvent //----------------------------------------------------------------------------- CChoreoEvent *CChoreoScene::FindTargetingEvent( const char *wavname, const char *name ) { for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; for ( int k = 0 ; k < c->GetNumEvents(); k++ ) { CChoreoEvent *e = c->GetEvent( k ); if ( !e ) continue; if ( !e->IsUsingRelativeTag() ) continue; if ( stricmp( wavname, e->GetRelativeWavName() ) ) continue; if ( stricmp( name, e->GetRelativeTagName() ) ) continue; return e; } } } return NULL; } //----------------------------------------------------------------------------- // Purpose: // Input : *wavname - // *name - // Output : CEventRelativeTag //----------------------------------------------------------------------------- CEventRelativeTag *CChoreoScene::FindTagByName( const char *wavname, const char *name ) { for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; for ( int k = 0 ; k < c->GetNumEvents(); k++ ) { CChoreoEvent *e = c->GetEvent( k ); if ( !e ) continue; if ( e->GetType() != CChoreoEvent::SPEAK ) continue; // Search for tag by name if ( !strstr( e->GetParameters(), wavname ) ) continue; CEventRelativeTag *tag = e->FindRelativeTag( name ); if ( !tag ) continue; return tag; } } } return NULL; } //----------------------------------------------------------------------------- // Purpose: // Input : *filename - //----------------------------------------------------------------------------- void CChoreoScene::ExportEvents( const char *filename, CUtlVector< CChoreoEvent * >& events ) { if ( events.Count() <= 0 ) return; // Create a serialization buffer CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); FilePrintf( buf, 0, "// Choreo version 1: <%i> Exported Events\n", events.Count() ); // Save out the selected events. int i; for ( i = 0 ; i < events.Count(); i++ ) { CChoreoEvent *e = events[ i ]; if ( !e->GetActor() ) continue; FileSaveEvent( buf, 0, e ); } // Write it out baby FileHandle_t fh = g_pFullFileSystem->Open( filename, "wt" ); if (fh) { g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh ); g_pFullFileSystem->Close(fh); } } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - // *channel - // starttime - //----------------------------------------------------------------------------- void CChoreoScene::ImportEvents( ISceneTokenProcessor *tokenizer, CChoreoActor *actor, CChoreoChannel *channel ) { m_pTokenizer = tokenizer; while ( 1 ) { if ( !m_pTokenizer->GetToken( true ) ) { break; } if ( strlen( m_pTokenizer->CurrentToken() ) <= 0 ) break; if ( !Q_stricmp( m_pTokenizer->CurrentToken(), "event" ) ) { ParseEvent( actor, channel ); } else { m_pTokenizer->Error( "unexpected token %s\n", m_pTokenizer->CurrentToken() ); break; } } // Fixup time tags ReconcileTags(); } void CChoreoScene::SetSubScene( bool sub ) { m_bSubScene = sub; } bool CChoreoScene::IsSubScene( void ) const { return m_bSubScene; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CChoreoScene::GetSceneFPS( void ) const { return m_nSceneFPS; } //----------------------------------------------------------------------------- // Purpose: // Input : fps - //----------------------------------------------------------------------------- void CChoreoScene::SetSceneFPS( int fps ) { m_nSceneFPS = fps; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CChoreoScene::IsUsingFrameSnap( void ) const { return m_bUseFrameSnap; } //----------------------------------------------------------------------------- // Purpose: // Input : snap - //----------------------------------------------------------------------------- void CChoreoScene::SetUsingFrameSnap( bool snap ) { m_bUseFrameSnap = snap; } //----------------------------------------------------------------------------- // Purpose: // Input : t - // Output : float //----------------------------------------------------------------------------- float CChoreoScene::SnapTime( float t ) { if ( !IsUsingFrameSnap() ) return t; float fps = (float)GetSceneFPS(); Assert( fps > 0 ); int itime = (int)( t * fps + 0.5f ); t = (float)itime / fps; // FIXME: If FPS is set and "using grid", snap to proper fractional time value return t; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::ReconcileGestureTimes() { for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; c->ReconcileGestureTimes(); } } } int CChoreoScene::TimeZoomFirst() { return m_TimeZoomLookup.First(); } int CChoreoScene::TimeZoomNext( int i ) { return m_TimeZoomLookup.Next( i ); } int CChoreoScene::TimeZoomInvalid() const { return m_TimeZoomLookup.InvalidIndex(); } char const *CChoreoScene::TimeZoomName( int i ) { return m_TimeZoomLookup.GetElementName( i ); } //----------------------------------------------------------------------------- // Purpose: // Input : *tool - // Output : int //----------------------------------------------------------------------------- int CChoreoScene::GetTimeZoom( char const *tool ) { // If not present add it int idx = m_TimeZoomLookup.Find( tool ); if ( idx == m_TimeZoomLookup.InvalidIndex() ) { idx = m_TimeZoomLookup.Insert( tool, 100 ); } return m_TimeZoomLookup[ idx ]; } //----------------------------------------------------------------------------- // Purpose: // Input : *tool - // tz - //----------------------------------------------------------------------------- void CChoreoScene::SetTimeZoom( char const *tool, int tz ) { // If not present add it int idx = m_TimeZoomLookup.Find( tool ); if ( idx == m_TimeZoomLookup.InvalidIndex() ) { idx = m_TimeZoomLookup.Insert( tool, 100 ); } m_TimeZoomLookup[ idx ] = tz; } void CChoreoScene::ParseScaleSettings( ISceneTokenProcessor *tokenizer, CChoreoScene *scene ) { tokenizer->GetToken( true ); if ( stricmp( tokenizer->CurrentToken(), "{" ) ) tokenizer->Error( "expecting {\n" ); while ( 1 ) { // Parse until } tokenizer->GetToken( true ); if ( strlen( tokenizer->CurrentToken() ) <= 0 ) { tokenizer->Error( "expecting scalesettings data\n" ); break; } if ( !Q_stricmp( tokenizer->CurrentToken(), "}" ) ) break; char tool[ 256 ]; Q_strncpy( tool, tokenizer->CurrentToken(), sizeof( tool ) ); tokenizer->GetToken( false ); int tz = Q_atoi( tokenizer->CurrentToken() ); if ( tz <= 0 ) tz = 100; scene->SetTimeZoom( tool, tz ); } } // Merges two .vcd's together bool CChoreoScene::Merge( CChoreoScene *other ) { int acount = 0; int ccount = 0; int ecount = 0; // Look for events that don't have actor/channel set int i; for ( i = 0 ; i < other->m_Events.Count(); i++ ) { CChoreoEvent *e = other->m_Events[ i ]; if ( e->GetActor() ) continue; MEM_ALLOC_CREDIT(); // Make a copy of the other event and add it to this scene CChoreoEvent *newEvent = AllocEvent(); *newEvent = *e; newEvent->SetScene( this ); ecount++; } for ( i = 0 ; i < other->m_Actors.Count(); i++ ) { CChoreoActor *a = other->m_Actors[ i ]; // See if that actor already exists bool newActor = false; CChoreoActor *destActor = FindActor( a->GetName() ); if ( !destActor ) { newActor = true; destActor = AllocActor(); *destActor = *a; destActor->RemoveAllChannels(); acount++; } // Now we have a destination actor, work on channels for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *ch = a->GetChannel( j ); bool newChannel = false; CChoreoChannel *destChannel = NULL; destChannel = destActor->FindChannel( ch->GetName() ); if ( !destChannel ) { destChannel = AllocChannel(); *destChannel = *ch; destChannel->RemoveAllEvents(); newChannel = true; ccount++; } if ( newChannel ) { destActor->AddChannel( destChannel ); destChannel->SetActor( destActor ); } // Now we have a destination channel, work on events themselves for ( int k = 0 ; k < ch->GetNumEvents(); k++ ) { CChoreoEvent *e = ch->GetEvent( k ); // Just import them wholesale, no checking MEM_ALLOC_CREDIT(); CChoreoEvent *newEvent = AllocEvent(); *newEvent = *e; newEvent->SetScene( this ); destChannel->AddEvent( newEvent ); newEvent->SetChannel( destChannel ); newEvent->SetActor( destActor ); ecount++; } } } Msg( "Merged in (%i) actors, (%i) channels, and (%i) events\n", acount, ccount, ecount ); return ( ecount || acount || ccount ); } //----------------------------------------------------------------------------- // Purpose: Updates master/slave status info per channel //----------------------------------------------------------------------------- void CChoreoScene::ReconcileCloseCaption() { for ( int i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; for ( int j = 0; j < a->GetNumChannels(); j++ ) { CChoreoChannel *c = a->GetChannel( j ); if ( !c ) continue; c->ReconcileCloseCaption(); } } } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- char const *CChoreoScene::GetFilename() const { return m_szFileName; } void CChoreoScene::SetFileName( char const *fn ) { Q_strncpy( m_szFileName, fn, sizeof( m_szFileName ) ); } bool CChoreoScene::GetPlayingSoundName( char *pchBuff, int iBuffLength ) { for ( int i = 0; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetType() == CChoreoEvent::SPEAK && e->IsProcessing() ) { Q_strncpy( pchBuff, e->GetParameters(), iBuffLength ); return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: Returns true if this scene has speech events that haven't played yet //----------------------------------------------------------------------------- bool CChoreoScene::HasUnplayedSpeech() { for ( int i = 0; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetType() == CChoreoEvent::SPEAK ) { // Have we played it yet? if ( m_flCurrentTime < e->GetStartTime() ) return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: Returns true if this scene has flex animation events that are playing //----------------------------------------------------------------------------- bool CChoreoScene::HasFlexAnimation() { for ( int i = 0; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetType() == CChoreoEvent::FLEXANIMATION ) { // Have we played it yet? if ( m_flCurrentTime >= e->GetStartTime() && m_flCurrentTime <= e->GetEndTime() ) return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CChoreoScene::SetBackground( bool bIsBackground ) { m_bIsBackground = bIsBackground; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CChoreoScene::IsBackground( ) { return m_bIsBackground; } bool CChoreoScene::HasEventsOfType( CChoreoEvent::EVENTTYPE type ) const { return m_bitvecHasEventOfType.IsBitSet( type ); } // ICurveDataAccessor method bool CChoreoScene::CurveHasEndTime() { return true; } int CChoreoScene::GetDefaultCurveType() { return CURVE_CATMULL_ROM_TO_CATMULL_ROM; } bool CChoreoScene::SaveBinary( char const *pszBinaryFileName, char const *pPathID, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool ) { bool bret = false; CUtlBuffer buf; SaveToBinaryBuffer( buf, nTextVersionCRC, pStringPool ); if ( g_pFullFileSystem->FileExists( pszBinaryFileName, pPathID ) && !g_pFullFileSystem->IsFileWritable( pszBinaryFileName, pPathID ) ) { Warning( "Forcing '%s' to be writable!!!\n", pszBinaryFileName ); g_pFullFileSystem->SetFileWritable( pszBinaryFileName, true, pPathID ); } FileHandle_t fh = g_pFullFileSystem->Open( pszBinaryFileName, "wb", pPathID ); if ( FILESYSTEM_INVALID_HANDLE != fh ) { g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), fh ); g_pFullFileSystem->Close( fh ); // Success bret = true; } else { Warning( "Unable to open '%s' for writing!!!\n", pszBinaryFileName ); } return bret; } void CChoreoScene::SaveToBinaryBuffer( CUtlBuffer& buf, unsigned int nTextVersionCRC, IChoreoStringPool *pStringPool ) { buf.PutInt( SCENE_BINARY_TAG ); buf.PutChar( SCENE_BINARY_VERSION ); buf.PutInt( nTextVersionCRC ); // Look for events that don't have actor/channel set CUtlVector< CChoreoEvent * > eventList; int i; for ( i = 0 ; i < m_Events.Count(); i++ ) { CChoreoEvent *e = m_Events[ i ]; if ( e->GetActor() ) continue; eventList.AddToTail( e ); } int c = eventList.Count(); Assert( c <= 255 ); buf.PutUnsignedChar( c ); for ( i = 0; i < c; ++i ) { CChoreoEvent *e = eventList[ i ]; e->SaveToBuffer( buf, this, pStringPool ); } // Now serialize the actors themselves CUtlVector< CChoreoActor * > actorList; for ( i = 0 ; i < m_Actors.Count(); i++ ) { CChoreoActor *a = m_Actors[ i ]; if ( !a ) continue; actorList.AddToTail( a ); } c = actorList.Count(); Assert( c <= 255 ); buf.PutUnsignedChar( c ); for ( i = 0; i < c; ++i ) { CChoreoActor *a = actorList[ i ]; a->SaveToBuffer( buf, this, pStringPool ); } /* // compiled version strips out map name, only used by editor if ( m_szMapname[ 0 ] ) { FilePrintf( buf, 0, "mapname \"%s\"\n", m_szMapname ); } */ m_SceneRamp.SaveToBuffer( buf, pStringPool ); /* // compiled version strips out scale settings fps and snap, only used by editor FileSaveScaleSettings( buf, 0, this ); FilePrintf( buf, 0, "fps %i\n", m_nSceneFPS ); FilePrintf( buf, 0, "snap %s\n", m_bUseFrameSnap ? "on" : "off" ); */ buf.PutUnsignedChar( m_bIgnorePhonemes ); } //----------------------------------------------------------------------------- // Purpose: Static method to extract just the CRC from a binary .xcd file // Input : buf - // crc - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CChoreoScene::GetCRCFromBinaryBuffer( CUtlBuffer& buf, unsigned int& crc ) { bool bret = false; int pos = buf.TellGet(); int tag = buf.GetInt(); if ( tag == SCENE_BINARY_TAG ) { byte ver = buf.GetChar(); if ( ver == SCENE_BINARY_VERSION ) { bret = true; crc = (unsigned int)buf.GetInt(); } } buf.SeekGet( CUtlBuffer::SEEK_HEAD, pos ); return bret; } bool CChoreoScene::RestoreFromBinaryBuffer( CUtlBuffer& buf, char const *filename, IChoreoStringPool *pStringPool ) { Q_strncpy( m_szFileName, filename, sizeof( m_szFileName ) ); int tag = buf.GetInt(); if ( tag != SCENE_BINARY_TAG ) return false; byte ver = buf.GetChar(); if ( ver != SCENE_BINARY_VERSION ) return false; // Skip the CRC buf.GetInt(); int i; int eventCount = buf.GetUnsignedChar(); for ( i = 0; i < eventCount; ++i ) { MEM_ALLOC_CREDIT(); CChoreoEvent *e = AllocEvent(); Assert( e ); if ( e->RestoreFromBuffer( buf, this, pStringPool ) ) { continue; } return false; } int actorCount = buf.GetUnsignedChar(); for ( i = 0; i < actorCount; ++i ) { CChoreoActor *a = AllocActor(); Assert( a ); if ( a->RestoreFromBuffer( buf, this, pStringPool ) ) { continue; } return false; } if ( !m_SceneRamp.RestoreFromBuffer( buf, pStringPool ) ) { return false; } m_bIgnorePhonemes = ( buf.GetUnsignedChar( ) != 0 ); // FIXME: Are these ever needed on restore? // ReconcileTags(); // ReconcileGestureTimes(); ReconcileCloseCaption(); InternalDetermineEventTypes(); if ( CChoreoScene::s_bEditingDisabled ) { m_flPrecomputedStopTime = FindStopTime(); } return true; }