text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose:
  //
  // $NoKeywords: $
  //=============================================================================//
  
  #ifndef CHOREOEVENT_H
  #define CHOREOEVENT_H
  #ifdef _WIN32
  #pragma once
  #endif
  
  class CChoreoActor;
  class CChoreoChannel;
  class CChoreoEvent;
  class CChoreoScene;
  class IChoreoEventCallback;
  class CAudioMixer;
  class CUtlBuffer;
  class IChoreoStringPool;
  
  
  #include "tier1/utlstring.h"
  #include "tier1/utlvector.h"
  #include "expressionsample.h"
  #include "networkvar.h"
  #include "localflexcontroller.h"
  
  typedef CUtlString ChoreoStr_t;
  
  //-----------------------------------------------------------------------------
  // Purpose: SPEAK events can have "relative tags" that other objects can reference
  //  to specify their start times off of
  //-----------------------------------------------------------------------------
  class CEventRelativeTag
  {
  public:
      DECLARE_CLASS_NOBASE( CEventRelativeTag );
  
      enum
      {
          MAX_EVENTTAG_LENGTH = 128,
      };
  
                      CEventRelativeTag( CChoreoEvent *owner, const char *name, float percentage );
                      CEventRelativeTag( const CEventRelativeTag& src );
  
      const char      *GetName( void );
      float           GetPercentage( void );
      void            SetPercentage( float percentage );
  
      // Returns the corrected time based on the owner's length and start time
      float           GetStartTime( void );
      CChoreoEvent    *GetOwner( void );
      void            SetOwner( CChoreoEvent *event );
  
  protected:
  
      ChoreoStr_t     m_Name;
      float           m_flPercentage;
      CChoreoEvent    *m_pOwner;
  };
  
  //-----------------------------------------------------------------------------
  // Purpose: GESTURE events can have "absolute tags" (where the value is not a
  //  percentage, but an actual timestamp from the start of the event)
  //-----------------------------------------------------------------------------
  class CEventAbsoluteTag
  {
  public:
      enum
      {
          MAX_EVENTTAG_LENGTH = 128,
      };
  
                      CEventAbsoluteTag( CChoreoEvent *owner, const char *name, float percentage );
                      CEventAbsoluteTag( const CEventAbsoluteTag& src );
  
      const char      *GetName( void );
  
      float           GetPercentage( void );
      void            SetPercentage( float percentage );
  
      float           GetEventTime( void );
      void            SetEventTime( float t );
  
      float           GetAbsoluteTime( void );
      void            SetAbsoluteTime( float t );
  
      CChoreoEvent    *GetOwner( void );
      void            SetOwner( CChoreoEvent *event );
  
      void            SetLocked( bool bLocked );
      bool            GetLocked( void );
  
      void            SetLinear( bool bLinear );
      bool            GetLinear( void );
  
      void            SetEntry( bool bEntry );
      bool            GetEntry( void );
  
      void            SetExit( bool bExit );
      bool            GetExit( void );
  
  protected:
  
      ChoreoStr_t     m_Name;
      float           m_flPercentage;
      bool            m_bLocked:1;
      bool            m_bLinear:1;
      bool            m_bEntry:1;
      bool            m_bExit:1;
      CChoreoEvent    *m_pOwner;
  };
  
  //-----------------------------------------------------------------------------
  // Purpose: FLEXANIMATION events can have "timing tags" that are used to align and
  //  manipulate flex animation curves
  //-----------------------------------------------------------------------------
  class CFlexTimingTag : public CEventRelativeTag
  {
      DECLARE_CLASS( CFlexTimingTag, CEventRelativeTag );
  
  public:
                      CFlexTimingTag( CChoreoEvent *owner, const char *name, float percentage, bool locked );
                      CFlexTimingTag( const CFlexTimingTag& src );
  
      bool            GetLocked( void );
      void            SetLocked( bool locked );
  
  protected:
      bool            m_bLocked;
  };
  
  //-----------------------------------------------------------------------------
  // Purpose: A flex controller position can be animated over a period of time
  //-----------------------------------------------------------------------------
  class CFlexAnimationTrack
  {
  public:
      enum
      {
          MAX_CONTROLLER_NAME = 128,
      };
  
                          CFlexAnimationTrack( CChoreoEvent *event );
                          CFlexAnimationTrack( const CFlexAnimationTrack* src );
      virtual             ~CFlexAnimationTrack( void );
  
      void                SetEvent( CChoreoEvent *event );
      CChoreoEvent        *GetEvent( void );
  
      void                SetFlexControllerName( const char *name );
      char const          *GetFlexControllerName( void );
  
      void                SetComboType( bool combo );
      bool                IsComboType( void );
  
      void                SetMin( float value );
      void                SetMax( float value );
      float               GetMin( int type = 0 );
      float               GetMax( int type = 0 );
  
      bool                IsInverted( void );
      void                SetInverted( bool isInverted );
  
      int                 GetNumSamples( int type = 0 );
      CExpressionSample   *GetSample( int index, int type = 0 );
  
      bool                IsTrackActive( void );
      void                SetTrackActive( bool active );
  
      // returns scaled value for absolute time per left/right side
      float               GetIntensity( float time, int side = 0 );
  
      CExpressionSample   *AddSample( float time, float value, int type = 0 );
      void                RemoveSample( int index, int type = 0 );
      void                Clear( void );
  
      void                Resort( int type = 0 );
  
      // Puts in dummy start/end samples to spline to zero ( or 0.5 for
      //  left/right data) at the origins
      CExpressionSample   *GetBoundedSample( int number, bool& bClamped, int type = 0 );
  
      int                 GetFlexControllerIndex( int side = 0 );
      LocalFlexController_t   GetRawFlexControllerIndex( int side = 0 );
      void                SetFlexControllerIndex( LocalFlexController_t raw, int index, int side = 0 );
  
      // returns 0..1 value for 0..1 time fraction per mag/balance
      float               GetFracIntensity( float time, int type );
  
      // retrieves raw intensity values (for mag vs. left/right slider setting)
      float               GetSampleIntensity( float time );
      float               GetBalanceIntensity( float time );
  
      void                SetEdgeInfo( bool leftEdge, int curveType, float zero );
      void                GetEdgeInfo( bool leftEdge, int& curveType, float& zero ) const;
      void                SetEdgeActive( bool leftEdge, bool state );
      bool                IsEdgeActive( bool leftEdge ) const;
      int                 GetEdgeCurveType( bool leftEdge ) const;
      float               GetEdgeZeroValue( bool leftEdge ) const;
  
      float               GetDefaultEdgeZeroPos() const;
  
      void                SetServerSide( bool state );
      bool                IsServerSide() const;
  private:
      // remove any samples after endtime
      void                RemoveOutOfRangeSamples( int type );
  
      // returns scaled value for absolute time per mag/balance
      float               GetIntensityInternal( float time, int type );
  
  public:
      // returns the fractional (0..1) value for "zero" based on Min/Max ranges
      float               GetZeroValue( int type, bool leftSide );
  
  
  private:
      char                *m_pControllerName;
  
      // base track has range, combo is always 0..1
      float               m_flMin;
      float               m_flMax;
  
      // 0 == magnitude
      // 1 == left/right
      CUtlVector< CExpressionSample > m_Samples[ 2 ];
      int                             m_nFlexControllerIndex[ 2 ];
      LocalFlexController_t           m_nFlexControllerIndexRaw[ 2 ];
  
      // For left and right edge of type 0 flex data ( magnitude track )
      EdgeInfo_t              m_EdgeInfo[ 2 ];
  
      CChoreoEvent        *m_pEvent;
  
      // Is track active
      bool                m_bActive:1;
  
      // Is this a combo (magnitude + stereo) track
      bool                m_bCombo:1;
      bool                m_bServerSide:1;
  
      bool                m_bInverted; // track is displayed 1..0 instead of 0..1
  };
  
  
  //-----------------------------------------------------------------------------
  // Purpose: The generic scene event type
  //-----------------------------------------------------------------------------
  class CChoreoEvent : public ICurveDataAccessor
  {
  public:
      // Type of event this object represents
      typedef enum
      {
          // Don't know yet
          UNSPECIFIED = 0,
  
          // Section start/end
          SECTION,
  
          // Play an expression
          EXPRESSION,
  
          // Look at another actor
          LOOKAT,
  
          // Move to a location
          MOVETO,
  
          // Speak/visemes a wave file
          SPEAK,
  
          // Play a gesture
          GESTURE,
  
          // Play a sequence
          SEQUENCE,
  
          // Face another actor
          FACE,
  
          // Fire a trigger
          FIRETRIGGER,
  
          // One or more flex sliders animated over the course of the event time period
          FLEXANIMATION,
  
          // A contained .vcd file
          SUBSCENE,
  
          // Loop back to previous time (forever or up to N times)
          LOOP,
  
          // A time span during which the scene may be temporarily interrupted
          INTERRUPT,
  
          // A dummy event that is used to mark the .vcd end time
          STOPPOINT,
  
          // A time span during which this actor can respond to events happening in the world, etc.
          PERMIT_RESPONSES,
  
          // A string passed to the game code for interpretation
          GENERIC,
  
          // THIS MUST BE LAST!!!
          NUM_TYPES,
      } EVENTTYPE;
  
      enum
      {
          MAX_TAGNAME_STRING      = 128,
          MAX_CCTOKEN_STRING      = 64,
      };
  
      typedef enum
      {
          DEFAULT = 0,
          SIMULATION,
          DISPLAY,
      } TIMETYPE;
  
      typedef enum
      {
          CC_MASTER = 0,  // default, implied
          CC_SLAVE,
          CC_DISABLED,
  
          NUM_CC_TYPES,
      } CLOSECAPTION;
  
      static int  s_nGlobalID;
  
      // Construction
      CChoreoEvent( CChoreoScene *scene );
      CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name );
      CChoreoEvent( CChoreoScene *scene, EVENTTYPE type, const char *name, const char *param );
  
      // Assignment
      CChoreoEvent&   operator=(const CChoreoEvent& src );
  
      ~CChoreoEvent( void );
  
      // ICurveDataAccessor methods
      virtual bool    CurveHasEndTime();
      virtual int     GetDefaultCurveType();
  
      // Binary serialization
      void            SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
      bool            RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool );
  
      // Accessors
      EVENTTYPE       GetType( void );
      void            SetType( EVENTTYPE type );
  
      void            SetName( const char *name );
      const char      *GetName( void );
  
      void            SetParameters( const char *target );
      const char      *GetParameters( void );
      void            SetParameters2( const char *target );
      const char      *GetParameters2( void );
      void            SetParameters3( const char *target );
      const char      *GetParameters3( void );
  
      void            SetStartTime( float starttime );
      float           GetStartTime( void );
  
      void            SetEndTime( float endtime );
      float           GetEndTime( void );
  
      float           GetDuration( void );
  
      void            SetResumeCondition( bool resumecondition );
      bool            IsResumeCondition( void );
  
      void            SetLockBodyFacing( bool lockbodyfacing );
      bool            IsLockBodyFacing( void );
  
      void            SetDistanceToTarget( float distancetotarget );
      float           GetDistanceToTarget( void );
  
      void            SetForceShortMovement( bool bForceShortMovement );
      bool            GetForceShortMovement( void );
  
      void            SetSyncToFollowingGesture( bool bSyncToFollowingGesture );
      bool            GetSyncToFollowingGesture( void );
  
      void            SetPlayOverScript( bool bPlayOverScript );
      bool            GetPlayOverScript( void );
  
      int             GetRampCount( void ) { return m_Ramp.GetCount(); };
      CExpressionSample *GetRamp( int index ) { return m_Ramp.Get( index ); };
      CExpressionSample *AddRamp( float time, float value, bool selected ) { return m_Ramp.Add( time, value, selected ); };
      void            DeleteRamp( int index ) { m_Ramp.Delete( index ); };
      void            ClearRamp( void ) { m_Ramp.Clear(); };
      void            ResortRamp( void ) { m_Ramp.Resort( this ); };
      CCurveData      *GetRamp( void ) { return &m_Ramp; };
  
      float           GetRampIntensity( float time ) { return m_Ramp.GetIntensity( this, time ); };
  
      // Calculates weighting for a given time
      float           GetIntensity( float scenetime );
      float           GetIntensityArea( float scenetime );
  
      // Calculates 0..1 completion for a given time
      float           GetCompletion( float time );
  
      // An end time of -1.0f means that the events is just triggered at the leading edge
      bool            HasEndTime( void );
  
      // Is the event something that can be sized ( a wave file, e.g. )
      bool            IsFixedLength( void );
      void            SetFixedLength( bool isfixedlength );
  
      // Move the start/end/both times by the specified dt (fixes up -1.0f endtimes)
      void            OffsetStartTime( float dt );
      void            OffsetEndTime( float dt );
      void            OffsetTime( float dt );
  
      // Snap to scene framerate
      void            SnapTimes( void );
      float           SnapTime( float t );
  
      CChoreoScene    *GetScene( void );
      void            SetScene( CChoreoScene *scene );
  
      // The actor the event is associated with
      void            SetActor( CChoreoActor *actor );
      CChoreoActor    *GetActor( void );
  
      // The channel the event is associated with
      void            SetChannel( CChoreoChannel *channel );
      CChoreoChannel  *GetChannel( void );
  
      // Get a more involved description of the event
      const char      *GetDescription( void );
  
      void            ClearAllRelativeTags( void );
      int             GetNumRelativeTags( void );
      CEventRelativeTag *GetRelativeTag( int tagnum );
      CEventRelativeTag *FindRelativeTag( const char *tagname );
      void            AddRelativeTag( const char *tagname, float percentage );
      void            RemoveRelativeTag( const char *tagname );
  
      bool            IsUsingRelativeTag( void );
      void            SetUsingRelativeTag( bool usetag, const char *tagname = 0, const char *wavname = 0);
      const char      *GetRelativeTagName( void );
      const char      *GetRelativeWavName( void );
  
      // Absolute tags
      typedef enum
      {
          PLAYBACK = 0,   // new timeline     - FIXME: should be stored as an absolute time
          ORIGINAL,       // original timeline - FIXME: should be stored at a fixed percentage of event
  
          NUM_ABS_TAG_TYPES,
      } AbsTagType;
  
      void            SetGestureSequenceDuration( float duration );
      bool            GetGestureSequenceDuration( float& duration );
  
      void            ClearAllAbsoluteTags( AbsTagType type );
      int             GetNumAbsoluteTags( AbsTagType type );
      CEventAbsoluteTag *GetAbsoluteTag( AbsTagType type, int tagnum );
      CEventAbsoluteTag *FindAbsoluteTag( AbsTagType type, const char *tagname );
      void            AddAbsoluteTag( AbsTagType type, const char *tagname, float t );
      void            RemoveAbsoluteTag( AbsTagType type, const char *tagname );
      bool            VerifyTagOrder( void );
      float           GetOriginalPercentageFromPlaybackPercentage( float t );
      float           GetPlaybackPercentageFromOriginalPercentage( float t );
  
      static const char *NameForAbsoluteTagType( AbsTagType t );
      static AbsTagType   TypeForAbsoluteTagName( const char *name );
  
      void            RescaleGestureTimes( float newstart, float newend, bool bMaintainAbsoluteTagPositions );
      bool            PreventTagOverlap( void );
  
      CEventAbsoluteTag *FindEntryTag( AbsTagType type );
      CEventAbsoluteTag *FindExitTag( AbsTagType type );
  
      // Flex animation type
      int             GetNumFlexAnimationTracks( void );
      CFlexAnimationTrack     *GetFlexAnimationTrack( int index );
      CFlexAnimationTrack     *AddTrack( const char *controllername );
      CFlexAnimationTrack     *FindTrack( const char *controllername );
      void            RemoveTrack( int index );
      void            RemoveAllTracks( void );
      void            OnEndTimeChanged( void );
  
      bool            GetTrackLookupSet( void );
      void            SetTrackLookupSet( bool set );
  
      // Flex Timing Tags (used by editor only)
      void            ClearAllTimingTags( void );
      int             GetNumTimingTags( void );
      CFlexTimingTag  *GetTimingTag( int tagnum );
      CFlexTimingTag  *FindTimingTag( const char *tagname );
      void            AddTimingTag( const char *tagname, float percentage, bool locked );
      void            RemoveTimingTag( const char *tagname );
  
      // Subscene ( embedded .vcd ) support
      void            SetSubScene( CChoreoScene *scene );
      CChoreoScene    *GetSubScene( void );
  
      bool            IsProcessing( void ) const;
      void            StartProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
      void            ContinueProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
      void            StopProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
      bool            CheckProcessing( IChoreoEventCallback *cb, CChoreoScene *scene, float t );
      void            ResetProcessing( void );
  
      void            SetMixer( CAudioMixer *mixer );
      CAudioMixer     *GetMixer( void ) const;
  
      // Hack for LOOKAT in editor
      int             GetPitch( void ) const;
      void            SetPitch( int pitch );
      int             GetYaw( void ) const;
      void            SetYaw( int yaw );
  
      // For LOOP events
      void            SetLoopCount( int numloops );
      int             GetLoopCount( void );
      int             GetNumLoopsRemaining( void );
      void            SetNumLoopsRemaining( int loops );
  
      bool            IsMarkedForSave() const { return m_bMarkedForSave; }
      void            SetMarkedForSave( bool mark ) { m_bMarkedForSave = mark; }
  
      void            GetMovementStyle( char *style, int maxlen );
      void            GetDistanceStyle( char *style, int maxlen );
  
      int             GetGlobalID() const { return m_nGlobalID; }
  
      // Localization/CC support (close captioning and multiple wave file recombination)
      void            SetCloseCaptionType( CLOSECAPTION type );
      CLOSECAPTION    GetCloseCaptionType() const;
      void            SetCloseCaptionToken( char const *token );
      char const      *GetCloseCaptionToken() const;
      void            SetUsingCombinedFile( bool isusing );
      bool            IsUsingCombinedFile() const;
      void            SetRequiredCombinedChecksum( unsigned int checksum );
      unsigned int    GetRequiredCombinedChecksum();
      void            SetNumSlaves( int num );
      int             GetNumSlaves() const;
      void            SetLastSlaveEndTime( float t );
      float           GetLastSlaveEndTime() const;
      void            SetCloseCaptionTokenValid( bool valid );
      bool            GetCloseCaptionTokenValid() const;
  
      bool            ComputeCombinedBaseFileName( char *dest, int destlen, bool creategenderwildcard );
      bool            IsCombinedUsingGenderToken() const;
      void            SetCombinedUsingGenderToken( bool using_gender );
  
      bool            IsSuppressingCaptionAttenuation() const;
      void            SetSuppressingCaptionAttenuation( bool suppress );
  
      int             ValidateCombinedFile();
  
      // This returns false if the wave is CC_DISABLED or is a CC_SLAVE,
      //  otherwise it returns the actual m_szCCToken value, or if that's
      //  blank it'll return the sounds.txt entry name (m_szParameters)
      bool            GetPlaybackCloseCaptionToken( char *dest, int destlen );
  
      void            ClearEventDependencies();
      void            AddEventDependency( CChoreoEvent *other );
      void            GetEventDependencies( CUtlVector< CChoreoEvent * >& list );
  
      void            SetActive( bool state );
      bool            GetActive() const;
  
      void            SetDefaultCurveType( int nCurveType );
  
      // Turn enum into string and vice versa
      static EVENTTYPE TypeForName( const char *name );
      static const char *NameForType( EVENTTYPE type );
  
      // Turn enum into string and vice versa
      static CLOSECAPTION CCTypeForName( const char *name );
      static const char *NameForCCType( CLOSECAPTION type );
  
  private:
  
      // Declare copy constructor private to prevent accidental usage...
                      CChoreoEvent(const CChoreoEvent& src );
  
      void SaveFlexAnimationsToBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool );
      bool RestoreFlexAnimationsFromBuffer( CUtlBuffer& buf, IChoreoStringPool *pStringPool );
  
      float           GetBoundedAbsoluteTagPercentage( AbsTagType type, int tagnum );
  
      float           _GetIntensity( float time );
  
      // String bounds
      enum
      {
          MAX_CHOREOEVENT_NAME    = 128,
          MAX_PARAMETERS_STRING   = 128,
      };
  
      // Base initialization
      void            Init( CChoreoScene *scene );
  
      // Type of event
      byte            m_fType;
  
      // Close caption type
      byte            m_ccType;
  
      // Name of event
      ChoreoStr_t     m_Name;
  
      // Event parameters
      ChoreoStr_t     m_Parameters;
      ChoreoStr_t     m_Parameters2;
      ChoreoStr_t     m_Parameters3;
  
      // Event start time
      float           m_flStartTime;
  
      // Event end time ( -1.0f means no ending, just leading edge triggered )
      float           m_flEndTime;
  
      // Duration of underlying gesture sequence
      float           m_flGestureSequenceDuration;
  
      // For CChoreoEvent::LOOP
      int             m_nNumLoops; // -1 == no limit
      int             m_nLoopsRemaining;
  
      // Overall intensity curve
      CCurveData      m_Ramp;
  
      // Start time is computed based on length of item referenced by tagged name
      ChoreoStr_t     m_TagName;
      ChoreoStr_t     m_TagWavName;
  
      // Associated actor
      CChoreoActor    *m_pActor;
      // Associated channel
      CChoreoChannel  *m_pChannel;
  
      CUtlVector < CEventRelativeTag > m_RelativeTags;
      CUtlVector < CFlexTimingTag > m_TimingTags;
      CUtlVector < CEventAbsoluteTag > m_AbsoluteTags[ NUM_ABS_TAG_TYPES ];
  
      CUtlVector < CFlexAnimationTrack * > m_FlexAnimationTracks;
  
      CChoreoScene    *m_pSubScene;
      CAudioMixer     *m_pMixer;
  
      // Scene which owns this event
      CChoreoScene    *m_pScene;
  
      int             m_nPitch;
      int             m_nYaw;
  
      float           m_flDistanceToTarget;
  
      int             m_nGlobalID;
  
      ChoreoStr_t     m_CCToken;
      unsigned int    m_uRequiredCombinedChecksum;
      // on master only, the combined file must have the same checksum to be useable
      int             m_nNumSlaves;
      // Only set on master, helps UI draw underbar
      float           m_flLastSlaveEndTime;
      // true if the cc token was found in the cc manager's database
  
      CUtlVector< CChoreoEvent * >    m_Dependencies;
  
      int             m_nDefaultCurveType;
  
  public:
      // used only during scrubbing of looping sequences
      float           m_flPrevCycle;
      float           m_flPrevTime;
  
      // Flags
  
      bool            m_bFixedLength:1;
      // True if this event must be "finished" before the next section can be started
      //  after playback is paused from a globalevent
      bool            m_bResumeCondition:1;
      bool            m_bUsesTag:1;
      bool            m_bTrackLookupSet:1;
      bool            m_bProcessing:1;
      bool            m_bLockBodyFacing:1;
      // Purely for save/load
      bool            m_bMarkedForSave:1;
      bool            m_bUsingCombinedSoundFile:1;
      bool            m_bCCTokenValid:1;
      bool            m_bCombinedUsingGenderToken:1;
  
      bool            m_bSuppressCaptionAttenuation:1;
  
      bool            m_bForceShortMovement:1;
      bool            m_bSyncToFollowingGesture:1;
      bool            m_bActive:1;
      bool            m_bPlayOverScript:1;
  };
  
  #endif // CHOREOEVENT_H
  