//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *filename - 
//-----------------------------------------------------------------------------
void *CBaseFlex::FindSceneFile( const char *filename )
{
	// See if it's already loaded
	int i;
	for ( i = 0; i < m_FileList.Size(); i++ )
	{
		CFacialExpressionFile *file = m_FileList[ i ];
		if ( file && !stricmp( file->filename, filename ) )
		{
			return file->buffer;
		}
	}
	
	// Load file into memory
	FileHandle_t file = filesystem->Open( UTIL_VarArgs( "expressions/%s.vfe", filename ), "rb" );

	if ( !file )
		return NULL;

	int len = filesystem->Size( file );

	// read the file
	byte *buffer = new unsigned char[ len ];
	Assert( buffer );
	filesystem->Read( buffer, len, file );
	filesystem->Close( file );

	// Create scene entry
	CFacialExpressionFile *pfile = new CFacialExpressionFile();
	// Remember filename
	Q_strncpy( pfile->filename, filename ,sizeof(pfile->filename));
	// Remember data pointer
	pfile->buffer = buffer;
	// Add to list
	m_FileList.AddToTail( pfile );

	// Fill in translation table
	flexsettinghdr_t *pSettinghdr = ( flexsettinghdr_t * )pfile->buffer;
	Assert( pSettinghdr );
	for (i = 0; i < pSettinghdr->numkeys; i++)
	{
		*(pSettinghdr->pLocalToGlobal(i)) = FindFlexController( pSettinghdr->pLocalName( i ) );
	}

	// Return data
	return pfile->buffer;
}
void CFlex::EnsureTranslations( const flexsettinghdr_t *pSettinghdr )
{
	Assert( pSettinghdr );

	FS_LocalToGlobal_t entry( pSettinghdr );

	unsigned short idx = m_LocalToGlobal->Find( entry );
	if ( idx != m_LocalToGlobal->InvalidIndex() )
		return;

	entry.SetCount( pSettinghdr->numkeys );

	for ( int i = 0; i < pSettinghdr->numkeys; ++i )
	{
		entry.m_Mapping[ i ] = FindFlexController( pSettinghdr->pLocalName( i ) );
	}

	m_LocalToGlobal->Insert( entry );
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CNPC_Breen::Spawn()
{
	// Breen is allowed to use multiple models, because he has a torso version for monitors.
	// He defaults to his normal model.
	char *szModel = (char *)STRING( GetModelName() );
	if (!szModel || !*szModel)
	{
		szModel = "models/breen.mdl";
		SetModelName( AllocPooledString(szModel) );
	}

	Precache();
	SetModel( szModel );

	BaseClass::Spawn();

	SetHullType(HULL_HUMAN);
	SetHullSizeNormal();

	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_STEP );
	SetBloodColor( BLOOD_COLOR_RED );
	m_iHealth			= 8;
	m_flFieldOfView		= 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result )
	m_NPCState			= NPC_STATE_NONE;
	
	CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS | bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD );
	CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
	AddEFlags( EFL_NO_DISSOLVE | EFL_NO_MEGAPHYSCANNON_RAGDOLL | EFL_NO_PHYSCANNON_INTERACTION );

	NPCInit();

	DevMsg("Spawning Breen\n");
	m_faceAPI = GetFaceAPI();

	// head orientation
	m_poses.push_back(new DrivenFeature(this, POSE_YAW));
	m_poses.push_back(new DrivenFeature(this, POSE_PITCH));
	m_poses.push_back(new DrivenFeature(this, POSE_ROLL));
	// blink
	m_flexors.push_back(new DrivenFeature(this, RIGHT_LID_CLOSER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_LID_CLOSER));
	// right eyebrow
	m_flexors.push_back(new DrivenFeature(this, RIGHT_INNER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, RIGHT_OUTER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, RIGHT_LOWERER));
	// left eyebrow
	m_flexors.push_back(new DrivenFeature(this, LEFT_INNER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_OUTER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_LOWERER));
	// horizontal mouth movement
	m_flexors.push_back(new DrivenFeature(this, RIGHT_CORNER_PULLER));
	m_flexors.push_back(new DrivenFeature(this, RIGHT_PUCKERER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_CORNER_PULLER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_PUCKERER));
	// vertical mouth movement
	m_flexors.push_back(new DrivenFeature(this, RIGHT_UPPER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, RIGHT_CORNER_DEPRESSOR));
	m_flexors.push_back(new DrivenFeature(this, LEFT_UPPER_RAISER));
	m_flexors.push_back(new DrivenFeature(this, LEFT_CORNER_DEPRESSOR));
	// overall mouth movements
	m_flexors.push_back(new DrivenFeature(this, MOUTH_STRETCH));
	//m_flexors.push_back(new DrivenFeature(this, SMILE));

	m_lastThink = engine->Time();
	m_adaptive_p = 1.0f;
	m_lastTrackingTime = 0.0f;
	m_smileFlex = FindFlexController("smile");
	m_smileAmount = 0.0f;
	m_nextSmilePick = 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *event - 
//-----------------------------------------------------------------------------
void CBaseFlex::AddFlexAnimation( CExpressionInfo *info )
{
	if ( !info )
		return;

	CChoreoEvent *event = info->m_pEvent;
	if ( !event )
		return;

	CChoreoScene *scene = info->m_pScene;
	if ( !scene )
		return;

	if ( !event->GetTrackLookupSet() )
	{
		// Create lookup data
		for ( int i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
		{
			CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
			if ( !track )
				continue;

			if ( track->IsComboType() )
			{
				char name[ 512 ];
				Q_strncpy( name, "right_" ,sizeof(name));
				strcat( name, track->GetFlexControllerName() );

				track->SetFlexControllerIndex( 0, FindFlexController( name ), 0 );

				Q_strncpy( name, "left_" ,sizeof(name));
				strcat( name, track->GetFlexControllerName() );

				track->SetFlexControllerIndex( 0, FindFlexController( name ), 1 );
			}
			else
			{
				track->SetFlexControllerIndex( 0, FindFlexController( (char *)track->GetFlexControllerName() ) );
			}
		}

		event->SetTrackLookupSet( true );
	}

	float scenetime = scene->GetTime();

	float weight = event->GetIntensity( scenetime );

	// Compute intensity for each track in animation and apply
	// Iterate animation tracks
	for ( int i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
	{
		CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
		if ( !track )
			continue;

		// Disabled
		if ( !track->IsTrackActive() )
			continue;

		// Map track flex controller to global name
		if ( track->IsComboType() )
		{
			for ( int side = 0; side < 2; side++ )
			{
				int controller = track->GetFlexControllerIndex( side );

				// Get spline intensity for controller
				float flIntensity = track->GetIntensity( scenetime, side );
				if ( controller >= 0 )
				{
					float orig = GetFlexWeight( controller );
					SetFlexWeight( controller, orig * (1 - weight) + flIntensity * weight );
				}
			}
		}
		else
		{
			int controller = track->GetFlexControllerIndex( 0 );

			// Get spline intensity for controller
			float flIntensity = track->GetIntensity( scenetime, 0 );
			if ( controller >= 0 )
			{
				float orig = GetFlexWeight( controller );
				SetFlexWeight( controller, orig * (1 - weight) + flIntensity * weight );
			}
		}
	}

	info->m_bStarted = true;
}
float CBaseFlex::GetFlexWeight( char *szName )
{
	return GetFlexWeight( FindFlexController( szName ) );
}
void CBaseFlex::SetFlexWeight( char *szName, float value )
{
	SetFlexWeight( FindFlexController( szName ), value );
}