bool GetFirstSoundInScene( const char *pSceneFilename, char *pSoundName, int soundNameLen )
{
	CChoreoScene *pScene = HammerLoadScene( pSceneFilename );
	if ( !pScene )
		return false;
	
	for ( int i = 0; i < pScene->GetNumEvents(); i++ )
	{
		CChoreoEvent *e = pScene->GetEvent( i );
		if ( !e || e->GetType() != CChoreoEvent::SPEAK )
			continue;

		const char *pParameters = e->GetParameters();
		V_strncpy( pSoundName, pParameters, soundNameLen );
		delete pScene;
		return true;
	}
	
	delete pScene;
	return false;	
}
void CVCDFile::LoadSoundsFromScene( CChoreoScene *scene )
{
	if ( !scene )
		return;

	CChoreoEvent *e;

	int c = scene->GetNumEvents();
	for ( int i = 0; i < c; i++ )
	{
		e = scene->GetEvent( i );
		if ( !e )
			continue;

		if ( e->GetType() != CChoreoEvent::SPEAK )
			continue;

		CSoundEntry *se = new CSoundEntry( this, e->GetParameters() );
		m_Sounds.AddToTail( se );
	}
}
//-----------------------------------------------------------------------------
// 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 );
}
//-----------------------------------------------------------------------------
// Redraw to screen
//-----------------------------------------------------------------------------
void CChoreoGlobalEventWidget::redraw( CChoreoWidgetDrawHelper& drawHelper )
{
	if ( !getVisible() )
		return;

	CChoreoEvent *event = GetEvent();
	if ( !event )
		return;

	RECT rcTab;
	rcTab = getBounds();

	bool isLoop = false;
	COLORREF pointColor = COLOR_CHOREO_SEGMENTDIVIDER;
	COLORREF clr = COLOR_CHOREO_SEGMENTDIVIDER_BG;
	switch ( event->GetType() )
	{
	default:
		break;
	case CChoreoEvent::LOOP:
		{
			clr				= COLOR_CHOREO_LOOPPOINT_BG;
			pointColor		= COLOR_CHOREO_LOOPPOINT;
			isLoop			= true;
		}
		break;
	case CChoreoEvent::STOPPOINT:
		{
			clr				= COLOR_CHOREO_STOPPOINT_BG;
			pointColor		= COLOR_CHOREO_STOPPOINT;
		}
		break;
	}

	if ( IsSelected() )
	{
		InflateRect( &rcTab, 2, 2 );

		drawHelper.DrawTriangleMarker( rcTab, pointColor );

		InflateRect( &rcTab, -2, -2 );

		drawHelper.DrawTriangleMarker( rcTab, RGB( 240, 240, 220 ) );

	}
	else
	{
		drawHelper.DrawTriangleMarker( rcTab, pointColor );
	}

	RECT rcClient;
	drawHelper.GetClientRect( rcClient );

	RECT rcLine = rcTab;
	rcLine.top = rcTab.bottom + 2;
	rcLine.bottom = rcClient.bottom;
	rcLine.left = ( rcLine.left + rcLine.right ) / 2;
	rcLine.right = rcLine.left;

	if ( IsSelected() )
	{
		drawHelper.DrawColoredLine( clr, PS_DOT, 2, rcLine.left, rcLine.top, rcLine.right, rcLine.bottom );
	}
	else
	{
		drawHelper.DrawColoredLine( clr, PS_DOT, 1, rcLine.left, rcLine.top, rcLine.right, rcLine.bottom );
	}

	if ( event->GetType() == CChoreoEvent::STOPPOINT )
	{
		OffsetRect( &rcTab, -4, 15 );

		mxbitmapdata_t *image = CChoreoEventWidget::GetImage( event->GetType() );
		if ( image )
		{
			drawHelper.OffsetSubRect( rcTab );
			DrawBitmapToDC( drawHelper.GrabDC(), rcTab.left, rcTab.top, 16, 16, *image );	
		}
	}

	if ( !isLoop )
		return;

	COLORREF labelText = COLOR_INFO_TEXT;
	DrawLabel( drawHelper, labelText, rcLine.left, rcLine.top + 2, false );

	// Figure out loop spot
	float looptime = (float)atof( event->GetParameters() );

	// Find pixel for that
	bool clipped = false;
	int x = m_pView->GetPixelForTimeValue( looptime, &clipped );
	if ( clipped )
		return;

	rcLine.left = x;
	rcLine.right = x;

	clr = COLOR_CHOREO_LOOPPOINT_START_BG;
	drawHelper.DrawColoredLine( clr, PS_SOLID, 1, rcLine.left, rcLine.top, rcLine.right, rcLine.top + 28);

	DrawLabel( drawHelper, labelText, rcLine.left, rcLine.top + 2, true );
}
void CBaseEventPropertiesDialog::PopulateTagList( CEventParams *params )
{
	CChoreoScene *scene = params->m_pScene;
	if ( !scene )
		return;

	HWND control = GetControl( IDC_TAGS );
	if ( control )
	{
		SendMessage( control, CB_RESETCONTENT, 0, 0 ); 
		SendMessage( control, WM_SETTEXT , 0, (LPARAM)va( "\"%s\" \"%s\"", params->m_szTagName, params->m_szTagWav ) );

		for ( int i = 0; i < scene->GetNumActors(); i++ )
		{
			CChoreoActor *a = scene->GetActor( 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->GetNumRelativeTags() <= 0 )
						continue;

					// add each tag to combo box
					for ( int t = 0; t < e->GetNumRelativeTags(); t++ )
					{
						CEventRelativeTag *tag = e->GetRelativeTag( t );
						if ( !tag )
							continue;

						SendMessage( control, CB_ADDSTRING, 0, (LPARAM)va( "\"%s\" \"%s\"", tag->GetName(), e->GetParameters() ) ); 
					}
				}
			}
		}
	}
}
void ProcessVCD( CUtlDict< VCDList, int >& database, CUtlSymbol& vcdname )
{
    // vprint( 0, "Processing '%s'\n", g_Analysis.symbols.String( vcdname ) );

    // Load the .vcd
    char fullname[ 512 ];
    Q_snprintf( fullname, sizeof( fullname ), "%s", g_Analysis.symbols.String( vcdname ) );

    LoadScriptFile( fullname );

    CChoreoScene *scene = ChoreoLoadScene( fullname, NULL, &g_TokenProcessor, Con_Printf );
    if ( scene )
    {
        bool first = true;
        // Now iterate the events looking for speak events
        int c = scene->GetNumEvents();
        for ( int i = 0; i < c; i++ )
        {
            CChoreoEvent *e = scene->GetEvent( i );

            if ( e->GetType() == CChoreoEvent::MOVETO )
            {
                SpewMoveto( first, fullname, e );
                first = false;
            }

            if ( e->GetType() != CChoreoEvent::SPEAK )
                continue;

            // Look up sound in sound emitter system
            char const *wavename = soundemitter->GetWavFileForSound( e->GetParameters(), NULL );
            if ( !wavename || !wavename[ 0 ] )
            {
                continue;
            }

            char fullwavename[ 512 ];
            Q_snprintf( fullwavename, sizeof( fullwavename ), "%ssound\\%s",
                        gamedir, wavename );
            Q_FixSlashes( fullwavename );

            // Now add to proper slot
            VCDList *entry = NULL;

            // Add vcd to database
            int slot = database.Find( fullwavename );
            if ( slot == database.InvalidIndex() )
            {
                VCDList nullEntry;
                slot = database.Insert( fullwavename, nullEntry );
            }

            entry = &database[ slot ];
            if ( entry->vcds.Find( vcdname ) == entry->vcds.InvalidIndex() )
            {
                entry->vcds.AddToTail( vcdname );
            }
        }

        if ( vcdonly )
        {
            CheckForOverlappingFlexTracks( scene );
        }
    }

    delete scene;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBaseFlex::AddSceneExpressions( void )
{
	// Iterate expressions and look for active slots
	for ( int i = 0; i < m_Expressions.Count(); i++ )
	{
		CExpressionInfo *info = &m_Expressions[ i ];
		Assert( info );

		// FIXME:  Need a safe handle to m_pEvent in case of memory deletion?
		CChoreoEvent *event = info->m_pEvent;
		Assert( event );

		CChoreoScene *scene = info->m_pScene;
		Assert( scene );

		switch ( event->GetType() )
		{
		case CChoreoEvent::FLEXANIMATION:
			{
				if ( event->HasEndTime() )
				{
					AddFlexAnimation( info );
				}
			}
			break;
		case CChoreoEvent::EXPRESSION:
			{
				// Expressions have to have an end time!!!
				if ( event->HasEndTime() )
				{
					// Look up the actual strings
					const char *scenefile	= event->GetParameters();
					const char *name		= event->GetParameters2();
					
					// Have to find both strings
					if ( scenefile && name )
					{
						// Find the scene file
						flexsettinghdr_t *pExpHdr = ( flexsettinghdr_t * )FindSceneFile( scenefile );
						if ( pExpHdr )
						{
							flexsettinghdr_t  *pOverrideHdr = NULL;
							
							// Find overrides, if any exist
							studiohdr_t	*hdr = GetModelPtr();
							
							if ( hdr && scene_allowoverrides.GetBool() )
							{
								char overridefile[ 512 ];
								char shortname[ 128 ];
								char modelname[ 128 ];
								
								//Q_strncpy( modelname, modelinfo->GetModelName( model ) ,sizeof(modelname));
								Q_strncpy( modelname, hdr->name ,sizeof(modelname));
								
								// Fix up the name
								Extract_FileBase( modelname, shortname );
								
								Q_snprintf( overridefile,sizeof(overridefile), "%s/%s", shortname, scenefile );
								
								pOverrideHdr = ( flexsettinghdr_t * )FindSceneFile( overridefile );
							}
							
							float scenetime = scene->GetTime();
							
							float scale = event->GetIntensity( scenetime );
							
							// Add the named expression
							AddExpression( name, scale, pExpHdr, pOverrideHdr, !info->m_bStarted );
						}
					}
				}
			}
			break;
		case CChoreoEvent::SEQUENCE:
			{
				AddFlexSequence( info );
			}
			break;
		case CChoreoEvent::GESTURE:
			{
				AddFlexGesture( info );
			}
			break;
		default:
			break;
		}

		/*
		float scenetime = scene->GetTime();

		float scale = event->GetIntensity( scenetime );
		Msg( "%s %f : ", event->GetName(), scale );
	
		// Add the named expression
		AddExpression( name, scale, pExpHdr, pOverrideHdr, !info->m_bStarted );
		*/

		info->m_bStarted = true;
	}
}