csgo-2018-source/movieobjects/dmerig.cpp
2021-07-24 21:11:47 -07:00

668 lines
23 KiB
C++

//====== Copyright © 1996-2009, Valve Corporation, All rights reserved. =======
//
// Purpose: Implementation of the CDmeRig class, a class which groups a set of
// associated constraints and operators together, allowing operations to be
// performed on the group of elements. Also contains the implementation of
// CDmeRigAnimSetElements, a helper class used to store a list of elements which
// are all associated with a single animation set.
//
//=============================================================================
#include "movieobjects/dmerig.h"
#include "movieobjects/dmeanimationset.h"
#include "movieobjects/dmeoperator.h"
#include "movieobjects/dmeclip.h"
#include "movieobjects/dmetrackgroup.h"
#include "movieobjects/dmetrack.h"
#include "movieobjects/dmerigconstraintoperators.h"
#include "movieobjects/dmetransformcontrol.h"
#include "movieobjects/dmechannel.h"
#include "datamodel/dmelementfactoryhelper.h"
#include "tier1/fmtstr.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Expose this the classes to the scene database
IMPLEMENT_ELEMENT_FACTORY( DmeRigAnimSetElements, CDmeRigAnimSetElements );
IMPLEMENT_ELEMENT_FACTORY( DmeRig, CDmeRig );
//-------------------------------------------------------------------------------------------------
// Purpose: Provide post construction processing.
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::OnConstruction()
{
m_AnimationSet.Init( this, "animationSet" );
m_ElementList.Init( this, "elementList" );
m_HiddenGroups.Init( this, "hiddenGroups" );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Provide processing and cleanup before shutdown
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::OnDestruction()
{
}
//-------------------------------------------------------------------------------------------------
// Purpose: Set the animation set elements in the list are to be associated with, only allowed
// when the element list is empty.
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::SetAnimationSet( CDmeAnimationSet* pAnimationSet )
{
// The element list must be empty when the animation set is assigned.
Assert( m_ElementList.Count() == 0 );
if ( m_ElementList.Count() == 0 )
{
m_AnimationSet = pAnimationSet;
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Add an element to the list
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::AddElement( CDmElement *pElement )
{
if ( pElement == NULL )
return;
m_ElementList.AddToTail( pElement );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove the specified element from the list. Returns true if the element is found and
// removed, return false if the element could not be found.
//-------------------------------------------------------------------------------------------------
bool CDmeRigAnimSetElements::RemoveElement( CDmElement *pElement )
{
int index = m_ElementList.Find( pElement );
if ( index != m_ElementList.InvalidIndex() )
{
m_ElementList.Remove( index );
return true;
}
return false;
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove all of the elements from the list
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::RemoveAll()
{
m_ElementList.RemoveAll();
}
//-------------------------------------------------------------------------------------------------
// Purpose: Add all of the elements to the provided array
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::GetElements( CUtlVector< CDmElement* > &elementList ) const
{
int nElements = m_ElementList.Count();
for ( int iElement = 0; iElement < nElements; ++iElement )
{
CDmElement *pElement = m_ElementList[ iElement ];
if ( pElement )
{
elementList.AddToTail( pElement );
}
}
}
//-------------------------------------------------------------------------------------------------
// Add a control group to the list of hidden control groups
//-------------------------------------------------------------------------------------------------
void CDmeRigAnimSetElements::AddHiddenControlGroup( CDmeControlGroup *pControlGroup )
{
m_HiddenGroups.AddToTail( pControlGroup->GetName() );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Provide post construction processing.
//-------------------------------------------------------------------------------------------------
void CDmeRig::OnConstruction()
{
m_AnimSetList.Init( this, "animSetList" );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Provide processing and cleanup before shutdown
//-------------------------------------------------------------------------------------------------
void CDmeRig::OnDestruction()
{
}
//-------------------------------------------------------------------------------------------------
// Purpose: Add an element to the rig
//-------------------------------------------------------------------------------------------------
void CDmeRig::AddElement( CDmElement* pElement, CDmeAnimationSet *pAnimationSet )
{
if ( ( pElement == NULL ) || ( pAnimationSet == NULL ) )
return;
// Search for an element set with the specified
// animation set, if none is found, create one.
CDmeRigAnimSetElements *pAnimSetElementList = FindOrCreateAnimSetElementList( pAnimationSet );
if ( pAnimSetElementList )
{
pAnimSetElementList->AddElement( pElement );
}
}
//-------------------------------------------------------------------------------------------------
// Set the state of the specified control group and add it to list of control group modified by
// the rig
//-------------------------------------------------------------------------------------------------
void CDmeRig::HideControlGroup( CDmeControlGroup *pGroup )
{
if ( pGroup == NULL )
return;
CDmeAnimationSet *pAnimationSet = pGroup->FindAnimationSet( true );
if ( pAnimationSet == NULL )
return;
CDmeRigAnimSetElements *pAnimSetElementList = FindOrCreateAnimSetElementList( pAnimationSet );
if ( pAnimSetElementList)
{
pGroup->SetVisible( false );
pAnimSetElementList->AddHiddenControlGroup( pGroup );
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove an element from the rig
//-------------------------------------------------------------------------------------------------
void CDmeRig::RemoveElement( CDmElement *pElement, CDmeAnimationSet *pAnimationSet )
{
if ( pElement == NULL )
return;
// Search each of the animation set element lists for the specified element, if the element
// is found and removed from an animation set element list, stop and don't search the others,
// as each element should belong to only on animation set.
int nAnimSets = m_AnimSetList.Count();
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements )
{
if ( pAnimSetElements->AnimationSet() == pAnimationSet )
{
if ( pAnimSetElements->RemoveElement( pElement ) )
break;
}
}
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove an animation set and all associated elements from the group
//-------------------------------------------------------------------------------------------------
void CDmeRig::RemoveAnimationSet( CDmeAnimationSet *pAnimationSet )
{
int index = FindAnimSetElementList( pAnimationSet );
if ( index != m_AnimSetList.InvalidIndex() )
{
m_AnimSetList.Remove( index );
}
}
//-------------------------------------------------------------------------------------------------
// Determine if the rig has any animation sets associated with it
//-------------------------------------------------------------------------------------------------
bool CDmeRig::HasAnyAnimationSets() const
{
int nAnimSets = m_AnimSetList.Count();
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
if ( CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ] )
{
if ( CDmeAnimationSet *pAnimSet = pAnimSetElements->AnimationSet() )
return true;
}
}
return false;
}
//-------------------------------------------------------------------------------------------------
// Purpose: Get the list of animation sets in the group
//-------------------------------------------------------------------------------------------------
void CDmeRig::GetAnimationSets( CUtlVector< CDmeAnimationSet* > &animationSetList ) const
{
int nAnimSets = m_AnimSetList.Count();
animationSetList.EnsureCapacity( animationSetList.Count() + nAnimSets );
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements != NULL )
{
CDmeAnimationSet *pAnimSet = pAnimSetElements->AnimationSet();
if ( pAnimSet != NULL )
{
animationSetList.AddToTail( pAnimSet );
}
}
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Get the list of elements for the specified animation set
//-------------------------------------------------------------------------------------------------
void CDmeRig::GetAnimationSetElements( const CDmeAnimationSet* pAnimationSet, CUtlVector< CDmElement* > &elementList ) const
{
int nAnimSets = m_AnimSetList.Count();
// Count the number of total elements in all the animation sets
int nTotalElements = 0;
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements != NULL )
{
nTotalElements = pAnimSetElements->NumElements();
}
}
// Allocate enough space in the element list for all of the elements in the rig.
elementList.EnsureCapacity( elementList.Count() + nTotalElements );
// Add all the elements in the rig to the provided element list
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements != NULL )
{
pAnimSetElements->GetElements( elementList );
}
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Determine if the rig has any elements from the specified animation set
//-------------------------------------------------------------------------------------------------
bool CDmeRig::HasAnimationSet( const CDmeAnimationSet *pAnimationSet ) const
{
return ( FindAnimSetElementList( pAnimationSet ) != m_AnimSetList.InvalidIndex() );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Find the element list for the specified animation set
//-------------------------------------------------------------------------------------------------
int CDmeRig::FindAnimSetElementList( const CDmeAnimationSet *pAnimationSet ) const
{
int nAnimSets = m_AnimSetList.Count();
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements == NULL )
continue;
if ( pAnimSetElements->AnimationSet() == pAnimationSet )
{
return iAnimSet;
}
}
return m_AnimSetList.InvalidIndex();
}
//-------------------------------------------------------------------------------------------------
// Find the element list for the specified animation set or create one
//-------------------------------------------------------------------------------------------------
CDmeRigAnimSetElements *CDmeRig::FindOrCreateAnimSetElementList( CDmeAnimationSet *pAnimationSet )
{
int nIndex = FindAnimSetElementList( pAnimationSet );
if ( nIndex != m_AnimSetList.InvalidIndex() )
return m_AnimSetList[ nIndex ];
CDmeRigAnimSetElements *pAnimSetElementList = CreateElement< CDmeRigAnimSetElements >( CFmtStr( "rigElements_%s", pAnimationSet->GetName() ), GetFileId() );
if ( pAnimSetElementList )
{
pAnimSetElementList->SetAnimationSet( pAnimationSet );
m_AnimSetList.AddToTail( pAnimSetElementList );
}
return pAnimSetElementList;
}
//-------------------------------------------------------------------------------------------------
// Purpose: Build a list of all of the dag nodes which are influenced by rig, does not include
// dag nodes that are part of the rig.
//-------------------------------------------------------------------------------------------------
void CDmeRig::FindInfluencedDags( CUtlVector< CDmeDag* > &dagList ) const
{
// Count the total number of elements, this is done to calculate a good pre-allocation size for lists
int totalElements = 0;
int nAnimSets = m_AnimSetList.Count();
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
totalElements += m_AnimSetList[ iAnimSet ]->NumElements();
}
// First build a tree of all of the dag nodes that are part of the rig, we do this so that we
// can quickly determine if a dag which is influenced by some element of the rig is part of the
// rig and therefore should not be added to the list of influenced dag nodes.
CUtlVector< CDmElement* > elementList( 0, totalElements );
CUtlRBTree< const CDmeDag* > rigDags( 0, totalElements, DefLessFunc( const CDmeDag *) );
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
const CDmaElementArray< CDmElement > &animSetElements = m_AnimSetList[ iAnimSet ]->Elements();
int nElements = animSetElements.Count();
for ( int iElement = 0; iElement < nElements; ++iElement )
{
CDmElement *pElement = animSetElements[ iElement ];
if ( pElement )
{
elementList.AddToTail( pElement );
CDmeDag *pDag = CastElement< CDmeDag >( pElement );
if ( pDag )
{
rigDags.Insert( pDag );
}
}
}
}
// Now iterate through all of the elements that belong to the rig and find any dag nodes which
// are influenced by the rig elements. This is done by looking for any operators and then
// getting the output attributes of the operator and determining if any of those attributes
// belong to a dag node which is not part of the rig.
CUtlRBTree< CDmeDag* > influencedDags( 0, totalElements, DefLessFunc( CDmeDag *) );
CUtlVector< CDmAttribute* > outputAttributes( 0, 32 );
int nElements = elementList.Count();
for ( int iElement = 0; iElement < nElements; ++iElement )
{
CDmElement *pElement = elementList[ iElement ];
CDmeOperator *pOperator = CastElement< CDmeOperator >( pElement );
if ( pOperator )
{
outputAttributes.RemoveAll();
pOperator->GetOutputAttributes( outputAttributes );
int nAttributes = outputAttributes.Count();
for ( int iAttr = 0; iAttr < nAttributes; ++iAttr )
{
CDmAttribute *pAttr = outputAttributes[ iAttr ];
if ( pAttr == NULL )
continue;
CDmeDag *pDag = CastElement< CDmeDag >( pAttr->GetOwner() );
if ( pDag == NULL )
{
CDmeTransform *pTransform = CastElement< CDmeTransform >( pAttr->GetOwner() );
if ( pTransform )
{
pDag = pTransform->GetDag();
}
}
if ( pDag == NULL )
continue;
// Make sure the dag is not part of the rig, if
// not add it to the list of influenced dag nodes.
if ( rigDags.Find( pDag ) == rigDags.InvalidIndex() )
{
influencedDags.InsertIfNotFound( pDag );
}
}
}
}
// Copy the influenced dag nodes into the provided list
int nDagNodes = influencedDags.Count();
dagList.SetCount( nDagNodes );
for ( int iDag = 0; iDag < nDagNodes; ++iDag )
{
dagList[ iDag ] = influencedDags[ iDag ];
}
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove all of elements in the rig from the specified shot
//-------------------------------------------------------------------------------------------------
void CDmeRig::RemoveElementsFromShot( CDmeFilmClip *pShot )
{
// Find the animation set channels track group, this will be used to find
// the the channels clip for each of the animation sets referenced by the rig.
CDmeTrack *pAnimSetEditorTrack = NULL;
CDmeTrackGroup *pTrackGroup = pShot->FindOrAddTrackGroup( "channelTrackGroup" );
if ( pTrackGroup )
{
pAnimSetEditorTrack = pTrackGroup->FindOrAddTrack( "animSetEditorChannels", DMECLIP_CHANNEL );
}
int nAnimSets = m_AnimSetList.Count();
for ( int iAnimSet = 0; iAnimSet < nAnimSets; ++iAnimSet )
{
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ iAnimSet ];
if ( pAnimSetElements == NULL )
continue;
CDmeAnimationSet *pAnimSet = pAnimSetElements->AnimationSet();
if ( pAnimSet == NULL )
continue;
CDmeChannelsClip *pChannelsClip = NULL;
if ( pAnimSetEditorTrack )
{
pChannelsClip = CastElement< CDmeChannelsClip >( pAnimSetEditorTrack->FindNamedClip( pAnimSet->GetName() ) );
}
// Make a copy of the array since we may remove elements from the original while iterating
const CDmaElementArray< CDmElement > &elements = pAnimSetElements->Elements();
int nElements = elements.Count();
CUtlVector< DmElementHandle_t > elementHandles( 0, nElements );
for ( int iElement = 0; iElement < nElements; ++iElement )
{
CDmElement *pElement = elements[ iElement ];
if ( pElement )
{
elementHandles.AddToTail( pElement->GetHandle() );
}
}
int nElementHandles = elementHandles.Count();
for ( int iHandle = 0; iHandle < nElementHandles; ++iHandle )
{
// Get the element using its handle because it may have been destroyed already
CDmElement *pElement = GetElement< CDmElement >( elementHandles[ iHandle ] );
if ( pElement == NULL )
continue;
// If the element is an operator make sure it is removed from the
// list of operators maintained by the shot and animation set.
CDmeOperator *pOperator = CastElement< CDmeOperator >( pElement );
if ( pOperator )
{
pAnimSet->RemoveOperator( pOperator );
pShot->RemoveOperator( pOperator );
// If the element is a channel remove it from the animation set's channel clip.
if ( pChannelsClip )
{
CDmeChannel *pChannel = CastElement< CDmeChannel >( pElement );
if ( pChannel )
{
pChannelsClip->RemoveChannel( pChannel );
}
}
// If the element is a constraint reconnect the original
// channels of the constrained dag back to the transform.
CDmeRigBaseConstraintOperator *pConstraint = CastElement< CDmeRigBaseConstraintOperator >( pElement );
if ( pConstraint )
{
pConstraint->ReconnectTransformChannels();
}
}
else if ( pElement->IsA( CDmeDag::GetStaticTypeSymbol() ) )
{
CDmeDag *pDag = CastElement< CDmeDag >( pElement );
CDmeDag *pParent = pDag->GetParent();
if ( pParent )
{
// Make sure the parent hasn't already been destroyed
if ( g_pDataModel->GetElement( pParent->GetHandle() ) )
{
pParent->RemoveChild( pDag );
}
}
// If the dag has any constraints on it, remove them
CDmeRigBaseConstraintOperator::RemoveConstraintsFromDag( pDag );
}
else if ( ( pElement->GetType() == CDmElement::GetStaticTypeSymbol() ) || pElement->IsA( CDmeTransformControl::GetStaticTypeSymbol() ) )
{
// If the element is just only element assume it may be a control or if the element is
// a transform control try to remove it from the animation set's list of controls.
pAnimSet->RemoveControl( pElement );
}
// Destroy the element, this is done because many elements refer to each other so if undo is enabled
// the auto cleanup will not take place and the elements will persist until the undo history is cleared.
g_pDataModel->DestroyElement( pElement->GetHandle() );
} // For iElement
// Reset the visibility on control groups that were hidden by the rig
SetHiddenControlGroupVisibility( pAnimSetElements, true );
// Clear the element list since they have all been destroyed
pAnimSetElements->RemoveAll();
} // For iAnimSet
m_AnimSetList.RemoveAll();
}
//-------------------------------------------------------------------------------------------------
// Set the visibility of the control groups in the hidden list
//-------------------------------------------------------------------------------------------------
void CDmeRig::SetHiddenControlGroupVisibility( CDmeRigAnimSetElements *pAnimSetElements, bool bVisible )
{
CDmeAnimationSet *pAnimSet = pAnimSetElements->AnimationSet();
if ( pAnimSet == NULL )
return;
const CDmaStringArray &hiddenGroupList = pAnimSetElements->HiddenControlGroups();
int nNumGroups = hiddenGroupList.Count();
for ( int iGroup = 0; iGroup < nNumGroups; ++iGroup )
{
CDmeControlGroup *pGroup = pAnimSet->FindControlGroup( hiddenGroupList[ iGroup ] );
if ( pGroup )
{
pGroup->SetVisible( bVisible );
}
}
}
//-------------------------------------------------------------------------------------------------
// Hide all of the control groups in the rig's list of hidden control groups
//-------------------------------------------------------------------------------------------------
void CDmeRig::HideHiddenControlGroups( CDmeAnimationSet *pAnimationSet )
{
int nAnimSetIndex = FindAnimSetElementList( pAnimationSet );
if ( nAnimSetIndex == m_AnimSetList.InvalidIndex() )
return;
CDmeRigAnimSetElements *pAnimSetElements = m_AnimSetList[ nAnimSetIndex ];
if ( pAnimSetElements == NULL )
return;
SetHiddenControlGroupVisibility( pAnimSetElements, false );
}
//-------------------------------------------------------------------------------------------------
// Purpose: Remove the specified element from any rig which it may be associated with.
//-------------------------------------------------------------------------------------------------
void CDmeRig::RemoveElementFromRig( CDmElement *pElement )
{
if ( pElement == NULL )
return;
CUtlVector< CDmeRigAnimSetElements* > rigElementLists;
FindAncestorsReferencingElement( pElement, rigElementLists );
for ( int iList = 0; iList < rigElementLists.Count(); ++iList )
{
CDmeRigAnimSetElements *pElementList = rigElementLists[ iList ];
if ( pElementList )
{
pElementList->RemoveElement( pElement );
}
}
}
//-------------------------------------------------------------------------------------------------
// Find all of the rigs which refer to the specified animation set
//-------------------------------------------------------------------------------------------------
void CollectRigsOnAnimationSet( CDmeAnimationSet *pAnimSet, CUtlVector< CDmeRig* > &rigList )
{
CDmeFilmClip *pFilmClip = FindReferringElement< CDmeFilmClip >( pAnimSet, "animationSets" );
if ( pFilmClip == NULL )
return;
CDmeDag *pScene = pFilmClip->GetScene();
if ( !pScene || !pAnimSet )
return;
pScene->FindChildrenOfType( rigList );
int i = rigList.Count();
while ( --i >= 0 )
{
CDmeRig *pRig = rigList[ i ];
if ( !pRig || !pRig->HasAnimationSet( pAnimSet ) )
{
rigList.Remove( i );
}
}
}