csgo-2018-source/mdlobjects/dmesequence.cpp
2021-07-24 21:11:47 -07:00

646 lines
22 KiB
C++

//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. =====//
//
// Dme representation of QC: $sequence
//
//===========================================================================//
// Valve includes
#include "datamodel/dmelementfactoryhelper.h"
#include "movieobjects/dmeattributereference.h"
#include "movieobjects/dmeanimationlist.h"
#include "movieobjects/dmechannel.h"
#include "movieobjects/dmeconnectionoperator.h"
#include "movieobjects/dmedag.h"
#include "mdlobjects/dmeanimcmd.h"
#include "mdlobjects/dmeik.h"
#include "mdlobjects/dmemotioncontrol.h"
#include "mdlobjects/dmesequence.h"
#include "mdlobjects/dmebonemask.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// CDmeAnimationEvent
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeAnimationEvent, CDmeAnimationEvent );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAnimationEvent::OnConstruction()
{
m_nFrame.Init( this, "frame" );
m_sDataString.Init( this, "dataString" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAnimationEvent::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceActivity
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceActivity, CDmeSequenceActivity );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceActivity::OnConstruction()
{
m_nWeight.InitAndSet( this, "weight", 1.0 );
m_sModifierList.Init( this, "modifierList" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceActivity::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceBlendBase
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceBlendBase, CDmeSequenceBlendBase );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlendBase::OnConstruction()
{
m_sPoseParameterName.Init( this, "poseParameterName" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlendBase::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceBlend
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceBlend, CDmeSequenceBlend );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlend::OnConstruction()
{
m_flParamStart.Init( this, "paramStart" );
m_flParamEnd.Init( this, "paramEnd" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlend::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceCalcBlend
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceCalcBlend, CDmeSequenceCalcBlend );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceCalcBlend::OnConstruction()
{
m_sAttachmentName.Init( this, "attachmentName" );
m_eMotionControl.InitAndCreate( this, "motionControl" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceCalcBlend::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceLayerBase
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceLayerBase, CDmeSequenceLayerBase );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceLayerBase::OnConstruction()
{
m_eAnimation.Init( this, "animation" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceLayerBase::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceAddLayer
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceAddLayer, CDmeSequenceAddLayer );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceAddLayer::OnConstruction()
{
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceAddLayer::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceBlendLayer
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceBlendLayer, CDmeSequenceBlendLayer );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlendLayer::OnConstruction()
{
m_flStartFrame.Init( this, "startFrame" );
m_flPeakFrame.Init( this, "peakFrame" );
m_flTailFrame.Init( this, "tailFrame" );
m_flEndFrame.Init( this, "endFrame" );
m_bSpline.Init( this, "spline" );
m_bCrossfade.Init( this, "crossfade" );
m_bNoBlend.Init( this, "noBlend" );
m_bLocal.Init( this, "local" );
m_sPoseParameterName.Init( this, "poseParameterName" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBlendLayer::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// CDmeSequenceBase
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequenceBase, CDmeSequenceBase );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBase::OnConstruction()
{
m_eActivity.InitAndCreate( this, "activity" );
m_bHidden.InitAndSet( this, "hidden", false );
m_bDelta.InitAndSet( this, "delta", false );
m_bWorldSpace.InitAndSet( this, "worldSpace", false );
m_bPreDelta.InitAndSet( this, "preDelta", false );
m_bAutoPlay.InitAndSet( this, "autoPlay", false );
m_bRealtime.InitAndSet( this, "realtime", false );
m_flFadeIn.InitAndSet( this, "fadein", 0.2f );
m_flFadeOut.InitAndSet( this, "fadeout", 0.2f );
m_sEntryNode.Init( this, "entryNode" );
m_sExitNode.Init( this, "exitNode" );
m_bReverseNodeTransition.Init( this, "reverseNodeTransition" );
m_bSnap.Init( this, "snap" );
m_bPost.Init( this, "post" );
m_bLoop.Init( this, "loop" );
m_eIkLockList.Init( this, "ikLockList", FATTRIB_NEVERCOPY );
m_eAnimationEventList.Init( this, "animationEventList" );
m_eLayerList.Init( this, "layerList" );
m_sKeyValues.Init( this, "keyValues" );
if ( m_eActivity.GetElement() )
{
if ( !Q_strcmp( "unnamed", m_eActivity.GetElement()->GetName() ) )
{
m_eActivity.GetElement()->SetName( "" );
}
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequenceBase::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// qsort function for sorting DmeBaseSequence elements based on type and
// sequence references.
//
// * A DmeBaseSequence must be either a DmeSequence or a DmeMultiSequence
// They are mutually exclusive, cannot be both
// * DmeMultiSequence refer to DmeSequence's so should always go last
// * DmeMultiSequence cannot refer to other DmeMultiSequence so they are
// considered equal
// * DmeSequence can refer to other DmeSequence elements via DmeAnimCmd's
// but circular references are not allowed. If a DmeSequence refers
// to another, the DmeSequence being referenced needs to be before the
// DmeSequence doing the referring
// * If no referrals between two DmeSequence's, sort based on DmeAnimCmd count
// so DmeSequence's with fewer DmeAnimCmd's go first
//-----------------------------------------------------------------------------
int CDmeSequenceBase::QSortFunction( const void *pVoidSeq1, const void *pVoidSeq2 )
{
const CDmeSequenceBase *pBaseSeq1 = *( const CDmeSequenceBase ** )pVoidSeq1;
const CDmeSequenceBase *pBaseSeq2 = *( const CDmeSequenceBase ** )pVoidSeq2;
if ( !pBaseSeq1 || !pBaseSeq2 )
return 0;
const CDmeSequence* pSeq1 = CastElement< CDmeSequence >( pBaseSeq1 ); // NULL if MultiSequence
const CDmeSequence* pSeq2 = CastElement< CDmeSequence >( pBaseSeq2 ); // NULL if MultiSequence
if ( pSeq1 && !pSeq2 ) // 1 Seq, 2 Multi, 1 < 2
return -1;
if ( !pSeq1 && pSeq2 ) // 1 Multi, 2 Seq, 1 > 2
return 1;
if ( !pSeq1 && !pSeq2 ) // Both Multi, 1 == 2, Multi can't refer to other multi
return 0;
// Both Seq, check for references
bool bRef[2] = { false, false };
const CDmeSequence *const pSeq[2] = { pSeq1, pSeq2 };
for ( int i = 0; i < 2; ++i )
{
for ( int j = 0; j < pSeq[i]->m_eAnimationCommandList.Count(); ++j )
{
const CDmeAnimCmd *pAnimCmd = pSeq[i]->m_eAnimationCommandList[j];
const CDmeAnimCmdSubtract *pAnimCmdSubtract = CastElement< CDmeAnimCmdSubtract >( pAnimCmd );
if ( pAnimCmdSubtract && pAnimCmdSubtract->m_eAnimation.GetHandle() == pSeq[ (i + 1) % 2 ]->GetHandle() )
{
bRef[i] = true;
break;
}
else
{
const CDmeAnimCmdAlign *pAnimCmdAlign = CastElement< CDmeAnimCmdAlign >( pAnimCmd );
if ( pAnimCmdAlign && pAnimCmdAlign->m_eAnimation.GetHandle() == pSeq[ ( i + 1 ) % 2 ]->GetHandle() )
{
bRef[i] = true;
break;
}
}
}
}
if ( bRef[0] && !bRef[1] ) // 1 references 2, so 1 > 2
return 1;
if ( !bRef[0] && bRef[1] ) // 1 references by 2, so 1 < 2
return -1;
if ( bRef[0] && bRef[1] )
{
Error( "Animation %s & %s reference each other, circular references are not allowed\n", pSeq1->GetName(), pSeq2->GetName() );
return 0;
}
if ( pSeq1->m_eAnimationCommandList.Count() < pSeq2->m_eAnimationCommandList.Count() )
{
return -1;
}
else if ( pSeq1->m_eAnimationCommandList.Count() > pSeq2->m_eAnimationCommandList.Count() )
{
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------
// CDmeSequence
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSequence, CDmeSequence );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequence::OnConstruction()
{
m_eSkeleton.Init( this, "skeleton" );
m_eAnimationList.Init( this, "animationList" );
m_flFPS.InitAndSet( this, "fps", 30.0f );
m_vOrigin.InitAndSet( this, "origin", Vector( 0.0f, 0.0f, 0.0f ) );
m_flScale.InitAndSet( this, "scale", 1.0f );
m_nStartLoop.Init( this, "startLoop" );
m_bForceLoop.Init( this, "forceLoop" );
m_bAutoIk.Init( this, "autoIk" );
m_flMotionRollback.InitAndSet( this, "motionRollback", 0.3f );
m_bAnimBlocks.InitAndSet( this, "animBlocks", true );
m_bAnimBlockStall.InitAndSet( this, "animBlockStall", true );
m_eMotionControl.InitAndCreate( this, "motionControl" );
m_eAnimationCommandList.Init( this, "animationCommandList" );
m_eIkRuleList.Init( this, "ikRuleList", FATTRIB_NEVERCOPY );
m_eBoneMask.Init( this, "boneMask" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequence::OnDestruction()
{
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeChannelsClip *CDmeSequence::GetDmeChannelsClip() const
{
CDmeAnimationList *pDmeAnimationList = m_eAnimationList.GetElement();
if ( !pDmeAnimationList )
return NULL;
for ( int i = 0; i < pDmeAnimationList->GetAnimationCount(); ++i )
{
CDmeChannelsClip *pDmeChannelsClip = pDmeAnimationList->GetAnimation( i );
if ( pDmeChannelsClip )
return pDmeChannelsClip;
}
return NULL;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
DmeFramerate_t CDmeSequence::GetFrameRate(
DmeFramerate_t fallbackFrameRate /* = 30 */,
bool bForceFallback /* = false */ ) const
{
CDmeChannelsClip *pDmeChannelsClip = GetDmeChannelsClip();
if ( !pDmeChannelsClip )
return fallbackFrameRate;
DmeFramerate_t dmeFrameRate = fallbackFrameRate;
if ( !bForceFallback && pDmeChannelsClip->HasAttribute( "frameRate" ) )
{
const int nFrameRate = pDmeChannelsClip->GetValue< int >( "frameRate", 0 );
if ( nFrameRate >= 0 )
{
dmeFrameRate = DmeFramerate_t( nFrameRate );
}
}
return dmeFrameRate;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CDmeSequence::GetFrameCount(
DmeFramerate_t fallbackFrameRate /* = 30 */,
bool bForceFallback /* = false */ ) const
{
CDmeChannelsClip *pDmeChannelsClip = GetDmeChannelsClip();
if ( !pDmeChannelsClip )
return 0;
const DmeFramerate_t dmeFrameRate = GetFrameRate( fallbackFrameRate, bForceFallback );
const DmeTime_t nStartTime = pDmeChannelsClip->GetStartTime();
const int nStartFrame = FrameForTime( nStartTime, dmeFrameRate );
const DmeTime_t nEndTime = pDmeChannelsClip->GetEndTime();
const int nEndFrame = FrameForTime( nEndTime, dmeFrameRate );
return nEndFrame - nStartFrame + 1;
}
//-----------------------------------------------------------------------------
// Does a search through connection operators for dependent DmeOperators
//-----------------------------------------------------------------------------
void CDmeSequence::GetDependentOperators( CUtlVector< IDmeOperator * > &operatorList, CDmeOperator *pDmeOperator ) const
{
if ( !pDmeOperator || !CastElement< CDmeOperator >( pDmeOperator ) )
return;
// Abort if the specified operator is already in the operatorList
for ( int i = 0; i < operatorList.Count(); ++i )
{
CDmeOperator *pTmpDmeOperator = CastElement< CDmeOperator >( reinterpret_cast< CDmeOperator * >( operatorList[i] ) );
if ( pTmpDmeOperator && pTmpDmeOperator == pDmeOperator )
return;
}
operatorList.AddToTail( pDmeOperator );
CUtlVector< CDmAttribute * > outAttrList;
pDmeOperator->GetOutputAttributes( outAttrList );
for ( int i = 0; i < outAttrList.Count(); ++i )
{
CDmElement *pDmElement = outAttrList[i]->GetOwner();
if ( !pDmElement )
continue;
if ( pDmElement != pDmeOperator )
{
CUtlVector< CDmElement * > reList0;
FindReferringElements( reList0, pDmElement, g_pDataModel->GetSymbol( "element" ), false );
for ( int j = 0; j < reList0.Count(); ++j )
{
CDmeAttributeReference *pRe0 = CastElement< CDmeAttributeReference >( reList0[j] );
if ( !pRe0 || pRe0->GetReferencedAttribute() != outAttrList[i] )
continue;
CUtlVector< CDmElement * > reList1;
FindReferringElements( reList1, pRe0, g_pDataModel->GetSymbol( "input" ), false );
for ( int k = 0; k < reList1.Count(); ++k )
{
CDmeConnectionOperator *pRe1 = CastElement< CDmeConnectionOperator >( reList1[k] );
if ( !pRe1 )
continue;
GetDependentOperators( operatorList, pRe1 );
}
}
}
GetDependentOperators( operatorList, CastElement< CDmeOperator >( pDmElement ) );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSequence::PrepareChannels( CUtlVector< IDmeOperator * > &dmeOperatorList )
{
dmeOperatorList.RemoveAll();
CDmeAnimationList *pDmeAnimationList = m_eAnimationList.GetElement();
if ( !pDmeAnimationList )
return;
for ( int i = 0; i < pDmeAnimationList->GetAnimationCount(); ++i )
{
CDmeChannelsClip *pDmeChannelsClip = pDmeAnimationList->GetAnimation( i );
if ( !pDmeChannelsClip )
continue;
for ( int j = 0; j < pDmeChannelsClip->m_Channels.Count(); ++j )
{
CDmeChannel *pDmeChannel = pDmeChannelsClip->m_Channels[j];
if ( !pDmeChannel )
continue;
pDmeChannel->SetMode( CM_PLAY );
GetDependentOperators( dmeOperatorList, pDmeChannel );
}
}
}
//-----------------------------------------------------------------------------
// Update channels so they are in position for the next frame
//-----------------------------------------------------------------------------
void CDmeSequence::UpdateChannels( CUtlVector< IDmeOperator * > &dmeOperatorList, DmeTime_t nClipTime )
{
CDmeAnimationList *pDmeAnimationList = m_eAnimationList.GetElement();
if ( !pDmeAnimationList )
return;
for ( int i = 0; i < pDmeAnimationList->GetAnimationCount(); ++i )
{
CDmeChannelsClip *pDmeChannelsClip = pDmeAnimationList->GetAnimation( i );
if ( !pDmeChannelsClip )
continue;
const DmeTime_t channelTime = pDmeChannelsClip->ToChildMediaTime( nClipTime );
const int nChannelsCount = pDmeChannelsClip->m_Channels.Count();
for ( int j = 0; j < nChannelsCount; ++j )
{
pDmeChannelsClip->m_Channels[j]->SetCurrentTime( channelTime );
}
}
// Recompute the position of the joints
{
CDisableUndoScopeGuard guard;
g_pDmElementFramework->SetOperators( dmeOperatorList );
g_pDmElementFramework->Operate( true );
}
g_pDmElementFramework->BeginEdit();
}
//-----------------------------------------------------------------------------
// CDmeMultiSequence
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeMultiSequence, CDmeMultiSequence );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeMultiSequence::OnConstruction()
{
m_nBlendWidth.InitAndSet( this, "blendWidth", 0 );
m_eBlendRef.Init( this, "blendRef", FATTRIB_NEVERCOPY );
m_eBlendComp.Init( this, "blendComp", FATTRIB_NEVERCOPY );
m_eBlendCenter.Init( this, "blendCenter", FATTRIB_NEVERCOPY );
m_eSequenceList.Init( this, "sequenceList", FATTRIB_NEVERCOPY );
m_eBlendList.Init( this, "blendList" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeMultiSequence::OnDestruction()
{
}