//========= Copyright Valve Corporation, All rights reserved. ============// // // Operators that generate combinations // //============================================================================= #ifndef DMECOMBINATIONOPERATOR_H #define DMECOMBINATIONOPERATOR_H #ifdef _WIN32 #pragma once #endif #include "datamodel/dmelement.h" #include "datamodel/dmattribute.h" #include "datamodel/dmattributevar.h" #include "movieobjects/dmeoperator.h" #include "movieobjects/dmeexpressionoperator.h" #include "datamodel/dmehandle.h" //----------------------------------------------------------------------------- // Expression operator //----------------------------------------------------------------------------- class CDmeChannel; class CDmeDag; class CDmElement; class CDmeChannelsClip; class CDmeShape; //----------------------------------------------------------------------------- // Control handles //----------------------------------------------------------------------------- typedef int ControlIndex_t; //----------------------------------------------------------------------------- // Basic version.. //----------------------------------------------------------------------------- class CDmeCombinationInputControl : public CDmElement { DEFINE_ELEMENT( CDmeCombinationInputControl, CDmElement ); public: virtual void OnElementUnserialized(); // Adds a control, returns the control index, // returns true if remapped control lists need updating bool AddRawControl( const char *pRawControlName ); // Removes controls // returns true if remapped control lists need updating bool RemoveRawControl( const char *pRawControlName ); void RemoveAllRawControls(); // Iterates remapped controls int RawControlCount() const; const char *RawControlName( int nIndex ) const; // Do we have a raw control? bool HasRawControl( const char *pRawControlName ) const; // Reordering controls void MoveRawControlUp( const char *pRawControlName ); void MoveRawControlDown( const char *pRawControlName ); // Is this control a stereo control? bool IsStereo() const; void SetStereo( bool bStereo ); // Is this control an eyelid control? bool IsEyelid() const; void SetEyelid( bool bEyelid ); // Returns the name of the eyeball const char *GetEyesUpDownFlexName() const; // Returns the wrinkle scale for a particular control float WrinkleScale( const char *pRawControlName ); float WrinkleScale( int nIndex ); void SetWrinkleScale( const char *pRawControlName, float flWrinkleScale ); float GetDefaultValue() const; float GetBaseValue() const; private: int FindRawControl( const char *pRawControlName ); CDmaStringArray m_RawControlNames; CDmaVar m_bIsStereo; CDmaVar< bool > m_bIsEyelid; // FIXME! Remove soon! Used to autogenerate wrinkle deltas CDmaArray< float > m_WrinkleScales; }; //----------------------------------------------------------------------------- // Basic version.. //----------------------------------------------------------------------------- class CDmeCombinationDominationRule : public CDmElement { DEFINE_ELEMENT( CDmeCombinationDominationRule, CDmElement ); public: // Methods of IDmElement virtual void OnAttributeChanged( CDmAttribute *pAttribute ); // Adds a dominating control void AddDominator( const char *pDominatorControl ); // Add a suppressed control void AddSuppressed( const char *pSuppressedControl ); // Remove all dominatior + suppressed controls void RemoveAllDominators(); void RemoveAllSuppressed(); // Iteration int DominatorCount() const; const char *GetDominator( int i ) const; int SuppressedCount() const; const char *GetSuppressed( int i ) const; // Search bool HasDominatorControl( const char *pDominatorControl ) const; bool HasSuppressedControl( const char *pSuppressedControl ) const; private: bool HasString( const char *pString, const CDmaStringArray& attr ); CDmaStringArray m_Dominators; CDmaStringArray m_Suppressed; }; //----------------------------------------------------------------------------- // Basic version.. needs channels to copy the data out of its output attributes //----------------------------------------------------------------------------- enum CombinationControlType_t { COMBO_CONTROL_FIRST = 0, COMBO_CONTROL_NORMAL = 0, COMBO_CONTROL_LAGGED, COMBO_CONTROL_TYPE_COUNT, }; class CDmeCombinationOperator : public CDmeOperator { DEFINE_ELEMENT( CDmeCombinationOperator, CDmeOperator ); public: // Methods of IDmElement virtual void OnAttributeChanged( CDmAttribute *pAttribute ); virtual void OnElementUnserialized(); // Adds a control, returns the control index. Also adds a raw control with the same name to this control ControlIndex_t FindOrCreateControl( const char *pControlName, bool bStereo, bool bAutoAddRawControl = false ); // Finds the index of the control with the specified name ControlIndex_t FindControlIndex( const char *pControlName ); // Changes a control's name void SetControlName( ControlIndex_t nControl, const char *pControlName ); // Removes a control void RemoveControl( const char *pControlName ); void RemoveAllControls(); // Adds a remapped control to a input control void AddRawControl( ControlIndex_t nControl, const char *pRawControlName ); // Removes an remapped control from a control void RemoveRawControl( ControlIndex_t nControl, const char *pRawControlName ); void RemoveAllRawControls( ControlIndex_t nControl ); // Iterates output controls associated with an input control int GetRawControlCount( ControlIndex_t nControl ) const; const char *GetRawControlName( ControlIndex_t nControl, int nIndex ) const; float GetRawControlWrinkleScale( ControlIndex_t nControl, int nIndex ) const; float GetRawControlWrinkleScale( ControlIndex_t nControl, const char *pRawControlName ) const; // Iterates a global list of output controls int GetRawControlCount( ) const; const char *GetRawControlName( int nIndex ) const; float GetRawControlWrinkleScale( int nIndex ) const; bool IsStereoRawControl( int nIndex ) const; bool IsEyelidRawControl( int nIndex ) const; // Gets Input Control Default & Base Values float GetControlDefaultValue( ControlIndex_t nControl ) const; float GetControlBaseValue( ControlIndex_t nControl ) const; // Do we have a raw control? bool HasRawControl( const char *pRawControlName ) const; // Sets the wrinkle scale for a particular raw control void SetWrinkleScale( ControlIndex_t nControlIndex, const char *pRawControlName, float flWrinkleScale ); // Sets the value of a control void SetControlValue( ControlIndex_t nControlIndex, float flValue, CombinationControlType_t type = COMBO_CONTROL_NORMAL ); // Sets the value of a stereo control void SetControlValue( ControlIndex_t nControlIndex, float flLevel, float flBalance, CombinationControlType_t type = COMBO_CONTROL_NORMAL ); void SetControlValue( ControlIndex_t nControlIndex, const Vector2D& vec, CombinationControlType_t type = COMBO_CONTROL_NORMAL ); // Returns true if a control is a stereo control void SetStereoControl( ControlIndex_t nControlIndex, bool bIsStereo ); bool IsStereoControl( ControlIndex_t nControlIndex ) const; // Sets the level of a control (only used by controls w/ 3 or more remappings) void SetMultiControlLevel( ControlIndex_t nControlIndex, float flLevel, CombinationControlType_t type = COMBO_CONTROL_NORMAL ); float GetMultiControlLevel( ControlIndex_t nControlIndex, CombinationControlType_t type = COMBO_CONTROL_NORMAL ) const; // Reordering controls void MoveControlUp( const char *pControlName ); void MoveControlDown( const char *pControlName ); void MoveControlBefore( const char *pDragControlName, const char *pDropControlName ); void MoveControlAfter( const char *pDragControlName, const char *pDropControlName ); void MoveRawControlUp( ControlIndex_t nControlIndex, const char *pRawControlName ); void MoveRawControlDown( ControlIndex_t nControlIndex, const char *pRawControlName ); // Returns true if a control is a multi control (a control w/ 3 or more remappings) bool IsMultiControl( ControlIndex_t nControlIndex ) const; // Returns true if a control is a multi-control which controls eyelids void SetEyelidControl( ControlIndex_t nControlIndex, bool bIsEyelid ); bool IsEyelidControl( ControlIndex_t nControlIndex ) const; const char *GetEyesUpDownFlexName( ControlIndex_t nControlIndex ) const; // Sets the value of a control float GetControlValue( ControlIndex_t nControlIndex, CombinationControlType_t type = COMBO_CONTROL_NORMAL ) const; const Vector2D& GetStereoControlValue( ControlIndex_t nControlIndex, CombinationControlType_t type = COMBO_CONTROL_NORMAL ) const; // Iterates controls int GetControlCount() const; const char *GetControlName( ControlIndex_t i ) const; // Attaches a channel to an input void AttachChannelToControlValue( ControlIndex_t nControlIndex, CombinationControlType_t type, CDmeChannel *pChannel ); // Adds a domination rule. Domination rules are specified using raw control names CDmeCombinationDominationRule *AddDominationRule( ); CDmeCombinationDominationRule *AddDominationRule( int nDominatorCount, const char **ppDominatorOutputControlNames, int nSuppressedCount, const char **ppSuppressedOutputControlNames ); CDmeCombinationDominationRule *AddDominationRule( const CUtlVector< const char * > dominators, const CUtlVector< const char * > suppressed ); CDmeCombinationDominationRule *AddDominationRule( CDmeCombinationDominationRule *pSrcRule ); // Removes a domination rule void RemoveDominationRule( int nIndex ); void RemoveDominationRule( CDmeCombinationDominationRule *pRule ); void RemoveAllDominationRules(); // Iteration int DominationRuleCount() const; CDmeCombinationDominationRule *GetDominationRule( int i ); // Rule reordering void MoveDominationRuleUp( CDmeCombinationDominationRule* pRule ); void MoveDominationRuleDown( CDmeCombinationDominationRule* pRule ); // Indicates we're using lagged control values void UsingLaggedData( bool bEnable ); bool IsUsingLaggedData() const; // Adds a target model/arbitrary element to perform the combinations on // The arbitrary element must have two attributes // "deltaStates", which is an array of elements // "deltaStateWeights", which is an array of floats // In the case of the model, it will look for all shapes in the dag hierarchy // and attempt to add that shape as a target // NOTE: Targets are not saved void AddTarget( CDmeDag *pDag ); void AddTarget( CDmElement *pElement ); void RemoveAllTargets(); // Used by studiomdl to discover the various combination rules int GetOperationTargetCount() const; CDmElement *GetOperationTarget( int nTargetIndex ); int GetOperationCount( int nTargetIndex ) const; CDmElement *GetOperationDeltaState( int nTargetIndex, int nOpIndex ); const CUtlVector< int > &GetOperationControls( int nTargetIndex, int nOpIndex ) const; int GetOperationDominatorCount( int nTargetIndex, int nOpIndex ) const; const CUtlVector< int > &GetOperationDominator( int nTargetIndex, int nOpIndex, int nDominatorIndex ) const; // Does one of the targets we refer to contain a particular delta state? bool DoesTargetContainDeltaState( const char *pDeltaStateName ); virtual void Operate(); virtual void Resolve(); virtual void GetInputAttributes ( CUtlVector< CDmAttribute * > &attrs ); virtual void GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs ); // Would a particular delta state attached to this combination operator end up stero? bool IsDeltaStateStereo( const char *pDeltaStateName ); void CopyControls( CDmeCombinationOperator *pSrc ); // FIXME: Remove soon! // This is a very short-term solution to the problem of autogenerating // wrinkle data; when we have real editors we can remove it void GenerateWrinkleDeltas( bool bOverwrite = true ); void SetToDefault(); // The base values are different from the default values see CDmeCombinationInputControl void SetToBase(); // Remove all controls and domination rules which are not referring to anything void Purge(); protected: void ComputeCombinationInfo( int nIndex ); private: typedef int RawControlIndex_t; struct DominatorInfo_t { CUtlVector< RawControlIndex_t > m_DominantIndices; CUtlVector< RawControlIndex_t > m_SuppressedIndices; }; struct CombinationOperation_t { int m_nDeltaStateIndex; CUtlVector< RawControlIndex_t > m_ControlIndices; CUtlVector< RawControlIndex_t > m_DominatorIndices; }; struct CombinationInfo_t { DmAttributeHandle_t m_hDestAttribute[COMBO_CONTROL_TYPE_COUNT]; CUtlVector< CombinationOperation_t > m_Outputs; }; struct RawControlInfo_t { CUtlString m_Name; bool m_bIsDefaultControl; ControlIndex_t m_InputControl; float m_flWrinkleScale; bool m_bLowerEyelid; Vector4D m_FilterRamp; // [0] = point at which ramp starts going up // [1] = point at which ramp hits 1.0 // [2] = point at which ramp stops holding at 1.0 // [3] = point at which ramp starts going down }; void ComputeCombinationInfo(); void CleanUpCombinationInfo( int nIndex ); void CleanUpCombinationInfo(); // Is a particular remapped control stereo? bool IsRawControlStereo( const char *pRawControlName ); // Determines the weighting of input controls based on the deltaState name int FindDeltaStateIndex( CDmAttribute *pDeltaArray, const char *pDeltaStateName ); // Determines which combination to use based on the deltaState name int ParseDeltaName( const char *pDeltaStateName, int *pControlIndices ); // Finds dominators void FindDominators( CombinationOperation_t& op ); // Computes lists of dominators and suppressors void RebuildDominatorInfo(); // Computes list of all remapped controls void RebuildRawControlList(); // Remaps non-stereo -> stereo, stereo ->left/right void ComputeInternalControlValue( RawControlIndex_t nRawControlIndex, CombinationControlType_t type, Vector2D &value ); // Computes lagged input values from non-lagged input void ComputeLaggedInputValues(); // Finds the index of the remapped control with the specified name RawControlIndex_t FindRawControlIndex( const char *pControlName, bool bIgnoreDefaultControls = false ) const; // Updates the default value associated with a control void UpdateDefaultValue( ControlIndex_t nControlIndex ); // Finds a domination rule int FindDominationRule( CDmeCombinationDominationRule *pRule ); // Generates wrinkle deltas for a dag hierarchy void GenerateWrinkleDeltas( CDmeShape *pShape, bool bOverwrite ); CDmaElementArray< CDmeCombinationInputControl > m_InputControls; CDmaArray< Vector > m_ControlValues[COMBO_CONTROL_TYPE_COUNT]; CDmaVar< bool > m_bSpecifyingLaggedData; CDmaElementArray< CDmeCombinationDominationRule > m_Dominators; CDmaElementArray< CDmElement > m_Targets; CUtlVector< bool > m_IsDefaultValue; // one per control value CUtlVector< RawControlInfo_t > m_RawControlInfo; CUtlVector< CombinationInfo_t > m_CombinationInfo; CUtlVector< DominatorInfo_t > m_DominatorInfo; float m_flLastLaggedComputationTime; }; //----------------------------------------------------------------------------- // Indicates we're using lagged control values //----------------------------------------------------------------------------- inline void CDmeCombinationOperator::UsingLaggedData( bool bEnable ) { m_bSpecifyingLaggedData = bEnable; } inline bool CDmeCombinationOperator::IsUsingLaggedData() const { return m_bSpecifyingLaggedData; } //----------------------------------------------------------------------------- // Helper method to create a lagged version of channel data from source data //----------------------------------------------------------------------------- void CreateLaggedVertexAnimation( CDmeChannelsClip *pClip, int nSamplesPerSec ); //----------------------------------------------------------------------------- // // A class used to edit combination operators in Maya.. doesn't connect to targets // //----------------------------------------------------------------------------- class CDmeMayaCombinationOperator : public CDmeCombinationOperator { DEFINE_ELEMENT( CDmeMayaCombinationOperator, CDmeCombinationOperator ); public: void AddDeltaState( const char *pDeltaStateName ); void RemoveDeltaState( const char *pDeltaStateName ); void RemoveAllDeltaStates(); int FindDeltaState( const char *pDeltaStateName ); int DeltaStateCount() const; const char *GetDeltaState( int nIndex ) const; const Vector2D& GetDeltaStateWeight( int nIndex, CombinationControlType_t type ) const; private: CDmaElementArray< CDmElement > m_DeltaStates; CDmaArray< Vector2D > m_DeltaStateWeights[COMBO_CONTROL_TYPE_COUNT]; }; #endif // DMECOMBINATIONOPERATOR_H