//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //===========================================================================// // Client-side CBasePlayer #ifndef C_STUDIOFLEX_H #define C_STUDIOFLEX_H #pragma once #include "c_baseanimating.h" #include "c_baseanimatingoverlay.h" #include "sceneentity_shared.h" #include "utlvector.h" //----------------------------------------------------------------------------- // Purpose: Item in list of loaded scene files //----------------------------------------------------------------------------- class CFlexSceneFile { public: enum { MAX_FLEX_FILENAME = 128, }; char filename[ MAX_FLEX_FILENAME ]; void *buffer; }; // For phoneme emphasis track struct Emphasized_Phoneme; class CSentence; enum { PHONEME_CLASS_WEAK = 0, PHONEME_CLASS_NORMAL, PHONEME_CLASS_STRONG, NUM_PHONEME_CLASSES }; // Mapping for each loaded scene file used by this actor struct FS_LocalToGlobal_t { explicit FS_LocalToGlobal_t() : m_Key( 0 ), m_nCount( 0 ), m_Mapping( 0 ) { } explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) : m_Key( key ), m_nCount( 0 ), m_Mapping( 0 ) { } void SetCount( int count ) { Assert( !m_Mapping ); Assert( count > 0 ); m_nCount = count; m_Mapping = new int[ m_nCount ]; Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) ); } FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src ) { m_Key = src.m_Key; delete m_Mapping; m_Mapping = new int[ src.m_nCount ]; Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) ); m_nCount = src.m_nCount; } ~FS_LocalToGlobal_t() { delete m_Mapping; m_nCount = 0; m_Mapping = 0; } const flexsettinghdr_t *m_Key; int m_nCount; int *m_Mapping; }; bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); class IHasLocalToGlobalFlexSettings { public: virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ) = 0; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- struct Emphasized_Phoneme { // Global fields, setup at start char classname[ 64 ]; bool required; // Global fields setup first time tracks played bool basechecked; const flexsettinghdr_t *base; const flexsetting_t *exp; // Local fields, processed for each sentence bool valid; float amount; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings { DECLARE_CLASS( C_BaseFlex, C_BaseAnimatingOverlay ); public: DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); DECLARE_INTERPOLATION(); C_BaseFlex(); virtual ~C_BaseFlex(); virtual void Spawn(); virtual void InitPhonemeMappings(); void SetupMappings( char const *pchFileRoot ); virtual CStudioHdr *OnNewModel( void ); virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); virtual void OnThreadedDrawSetup(); // model specific virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); static void LinkToGlobalFlexControllers( CStudioHdr *hdr ); virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual bool SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); static void RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime ); virtual void SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual bool UsesFlexDelayedWeights(); static void RunFlexRules( CStudioHdr *pStudioHdr, float *dest ); virtual Vector SetViewTarget( CStudioHdr *pStudioHdr ); virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); virtual void GetToolRecordingState( KeyValues *msg ); // Called at the lowest level to actually apply a flex animation void AddFlexAnimation( CSceneEventInfo *info ); void SetFlexWeight( LocalFlexController_t index, float value ); float GetFlexWeight( LocalFlexController_t index ); // Look up flex controller index by global name LocalFlexController_t FindFlexController( const char *szName ); public: Vector m_viewtarget; CInterpolatedVar< Vector > m_iv_viewtarget; // indexed by model local flexcontroller float m_flexWeight[MAXSTUDIOFLEXCTRL]; CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL > m_iv_flexWeight; int m_blinktoggle; static int AddGlobalFlexController( const char *szName ); static char const *GetGlobalFlexControllerName( int idx ); // bah, this should be unified with all prev/current stuff. public: // Keep track of what scenes are being played void StartChoreoScene( CChoreoScene *scene ); void RemoveChoreoScene( CChoreoScene *scene ); // Start the specifics of an scene event virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, C_BaseEntity *pTarget ); // Manipulation of events for the object // Should be called by think function to process all scene events // The default implementation resets m_flexWeight array and calls // AddSceneEvents virtual void ProcessSceneEvents( bool bFlexEvents ); // Assumes m_flexWeight array has been set up, this adds the actual currently playing // expressions to the flex weights and adds other scene events as needed virtual bool ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); virtual bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); // Remove all playing events void ClearSceneEvents( CChoreoScene *scene, bool canceled ); // Stop specifics of event virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); // Add the event to the queue for this actor void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false ); // Remove the event from the queue for this actor void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill ); // Checks to see if the event should be considered "completed" bool CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); // Checks to see if a event should be considered "completed" virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event ); int FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key ); // IHasLocalToGlobalFlexSettings virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); // For handling scene files void *FindSceneFile( const char *filename ); private: bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); void AddFlexSetting( const char *expr, float scale, const flexsettinghdr_t *pSettinghdr, bool newexpression ); // Array of active SceneEvents, in order oldest to newest CUtlVector < CSceneEventInfo > m_SceneEvents; CUtlVector < CChoreoScene * > m_ActiveChoreoScenes; bool HasSceneEvents() const; private: CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal; float m_blinktime; int m_prevblinktoggle; int m_iBlink; LocalFlexController_t m_iEyeUpdown; LocalFlexController_t m_iEyeRightleft; bool m_bSearchedForEyeFlexes; int m_iMouthAttachment; float m_flFlexDelayTime; float *m_flFlexDelayedWeight; int m_cFlexDelayedWeight; // shared flex controllers static int g_numflexcontrollers; static char *g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers static float g_flexweight[MAXSTUDIOFLEXDESC]; protected: Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ]; private: C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr ); void ProcessVisemes( Emphasized_Phoneme *classes ); void AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ); void AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ); bool SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ); void ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity ); #ifdef HL2_CLIENT_DLL public: Vector m_vecLean; CInterpolatedVar< Vector > m_iv_vecLean; Vector m_vecShift; CInterpolatedVar< Vector > m_iv_vecShift; #endif }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CFlexSceneFileManager : CAutoGameSystem { public: CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" ) { } virtual bool Init(); virtual void Shutdown(); void EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr ); void *FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO ); private: void DeleteSceneFiles(); CUtlVector< CFlexSceneFile * > m_FileList; }; //----------------------------------------------------------------------------- // Do we have active expressions? //----------------------------------------------------------------------------- inline bool C_BaseFlex::HasSceneEvents() const { return m_SceneEvents.Count() != 0; } EXTERN_RECV_TABLE(DT_BaseFlex); float *GetVisemeWeights( int phoneme ); #endif // C_STUDIOFLEX_H