summaryrefslogtreecommitdiff
path: root/sfmobjects/sfmanimationsetutils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sfmobjects/sfmanimationsetutils.cpp')
-rw-r--r--sfmobjects/sfmanimationsetutils.cpp891
1 files changed, 891 insertions, 0 deletions
diff --git a/sfmobjects/sfmanimationsetutils.cpp b/sfmobjects/sfmanimationsetutils.cpp
new file mode 100644
index 0000000..fb17a46
--- /dev/null
+++ b/sfmobjects/sfmanimationsetutils.cpp
@@ -0,0 +1,891 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// NOTE: This is a cut-and-paste hack job to get animation set construction
+// working from a commandline tool. It came from tools/ifm/createsfmanimation.cpp
+// This file needs to die almost immediately + be replaced with a better solution
+// that can be used both by the sfm + sfmgen.
+//
+//=============================================================================
+
+#include "sfmobjects/sfmanimationsetutils.h"
+#include "movieobjects/dmechannel.h"
+#include "movieobjects/dmeclip.h"
+#include "movieobjects/dmetrackgroup.h"
+#include "movieobjects/dmetrack.h"
+#include "movieobjects/dmecamera.h"
+#include "movieobjects/dmetimeselection.h"
+#include "movieobjects/dmeanimationset.h"
+#include "movieobjects/dmegamemodel.h"
+#include "sfmobjects/flexcontrolbuilder.h"
+#include "tier3/tier3.h"
+#include "bone_setup.h"
+#include "vstdlib/random.h"
+#include "tier1/KeyValues.h"
+#include "filesystem.h"
+#include "movieobjects/timeutils.h"
+
+
+#define ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE "cfg/SFM_DefaultAnimationGroups.txt"
+#define STANDARD_CHANNEL_TRACK_GROUP "channelTrackGroup"
+#define STANDARD_ANIMATIONSET_CHANNELS_TRACK "animSetEditorChannels"
+#define CLIP_PREROLL_TIME DmeTime_t( 5.0f )
+#define CLIP_POSTROLL_TIME DmeTime_t( 5.0f )
+
+
+//-----------------------------------------------------------------------------
+// Creates channels clip for the animation set
+//-----------------------------------------------------------------------------
+static CDmeChannelsClip* CreateChannelsClip( CDmeAnimationSet *pAnimationSet, CDmeFilmClip *pOwnerClip )
+{
+ CDmeTrackGroup *pTrackGroup = pOwnerClip->FindOrAddTrackGroup( "channelTrackGroup" );
+ if ( !pTrackGroup )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+
+ CDmeTrack *pAnimSetEditorTrack = pTrackGroup->FindOrAddTrack( "animSetEditorChannels", DMECLIP_CHANNEL );
+ Assert( pAnimSetEditorTrack );
+
+ CDmeChannelsClip *pChannelsClip = CreateElement< CDmeChannelsClip >( pAnimationSet->GetName(), pAnimationSet->GetFileId() );
+ pAnimSetEditorTrack->AddClip( pChannelsClip );
+
+ DmeTime_t childMediaTime = pOwnerClip->GetStartInChildMediaTime();
+ pChannelsClip->SetStartTime( childMediaTime - CLIP_PREROLL_TIME );
+ DmeTime_t childMediaDuration = pOwnerClip->ToChildMediaDuration( pOwnerClip->GetDuration() );
+ pChannelsClip->SetDuration( childMediaDuration + CLIP_PREROLL_TIME + CLIP_POSTROLL_TIME );
+ return pChannelsClip;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a constant valued log
+//-----------------------------------------------------------------------------
+template < class T >
+CDmeChannel *CreateConstantValuedLog( CDmeChannelsClip *channelsClip, const char *basename, const char *pName, CDmElement *pToElement, const char *pToAttr, const T &value )
+{
+ char name[ 256 ];
+ Q_snprintf( name, sizeof( name ), "%s_%s channel", basename, pName );
+
+ CDmeChannel *pChannel = CreateElement< CDmeChannel >( name, channelsClip->GetFileId() );
+ pChannel->SetMode( CM_PLAY );
+ pChannel->CreateLog( CDmAttributeInfo< T >::AttributeType() );
+ pChannel->SetOutput( pToElement, pToAttr );
+ pChannel->GetLog()->SetValueThreshold( 0.0f );
+
+ ((CDmeTypedLog< T > *)pChannel->GetLog())->InsertKey( DmeTime_t( 0 ), value );
+
+ channelsClip->m_Channels.AddToTail( pChannel );
+
+ return pChannel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Create channels for transform data
+//-----------------------------------------------------------------------------
+static void CreateTransformChannels( CDmeTransform *pTransform, const char *pBaseName, int bi, CDmeChannelsClip *pChannelsClip )
+{
+ char name[ 256 ];
+
+ // create, connect and cache bonePos channel
+ Q_snprintf( name, sizeof( name ), "%s_bonePos channel %d", pBaseName, bi );
+ CDmeChannel *pPosChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
+ pPosChannel->SetMode( CM_PLAY );
+ pPosChannel->CreateLog( AT_VECTOR3 );
+ pPosChannel->SetOutput( pTransform, "position" );
+ pPosChannel->GetLog()->SetValueThreshold( 0.0f );
+ pChannelsClip->m_Channels.AddToTail( pPosChannel );
+
+ // create, connect and cache boneRot channel
+ Q_snprintf( name, sizeof( name ), "%s_boneRot channel %d", pBaseName, bi );
+ CDmeChannel *pRotChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
+ pRotChannel->SetMode( CM_PLAY );
+ pRotChannel->CreateLog( AT_QUATERNION );
+ pRotChannel->SetOutput( pTransform, "orientation" );
+ pRotChannel->GetLog()->SetValueThreshold( 0.0f );
+ pChannelsClip->m_Channels.AddToTail( pRotChannel );
+}
+
+static void CreateAnimationLogs( CDmeChannelsClip *channelsClip, CDmeGameModel *pModel, studiohdr_t *pStudioHdr, const char *basename, int sequence, float flStartTime, float flDuration, float flTimeStep = 0.015f )
+{
+ Assert( pModel );
+ Assert( pStudioHdr );
+
+ CStudioHdr hdr( pStudioHdr, g_pMDLCache );
+
+ if ( sequence >= hdr.GetNumSeq() )
+ {
+ sequence = 0;
+ }
+
+ int numbones = hdr.numbones();
+
+ // make room for bones
+ CUtlVector< CDmeDag* > dags;
+ CUtlVector< CDmeChannel * > poschannels;
+ CUtlVector< CDmeChannel * > rotchannels;
+
+ dags.EnsureCapacity( numbones );
+ poschannels.EnsureCapacity( numbones );
+ rotchannels.EnsureCapacity( numbones );
+
+ Vector pos[ MAXSTUDIOBONES ];
+ Quaternion q[ MAXSTUDIOBONES ];
+
+ float poseparameter[ MAXSTUDIOPOSEPARAM ];
+ for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
+ {
+ poseparameter[ pp ] = 0.0f;
+ }
+
+ float flSequenceDuration = Studio_Duration( &hdr, sequence, poseparameter );
+ mstudioseqdesc_t &seqdesc = hdr.pSeqdesc( sequence );
+
+ bool created = false;
+
+ for ( float t = flStartTime; t <= flStartTime + flDuration; t += flTimeStep )
+ {
+ int bi;
+
+ if ( t > flStartTime + flDuration )
+ t = flStartTime + flDuration;
+
+ float flCycle = t / flSequenceDuration;
+
+ if ( seqdesc.flags & STUDIO_LOOPING )
+ {
+ flCycle = flCycle - (int)flCycle;
+ if (flCycle < 0) flCycle += 1;
+ }
+ else
+ {
+ flCycle = max( 0.f, min( flCycle, 0.9999f ) );
+ }
+
+ if ( !created )
+ {
+ created = true;
+
+ // create, connect and cache each bone's pos and rot channels
+ for ( bi = 0; bi < numbones; ++bi )
+ {
+ int nCount = channelsClip->m_Channels.Count();
+
+ CDmeTransform *pTransform = pModel->GetBone( bi );
+ CreateTransformChannels( pTransform, basename, bi, channelsClip );
+
+ CDmeChannel *pPosChannel = channelsClip->m_Channels[ nCount ];
+ CDmeChannel *pRotChannel = channelsClip->m_Channels[ nCount+1 ];
+ poschannels.AddToTail( pPosChannel );
+ rotchannels.AddToTail( pRotChannel );
+ }
+ }
+
+ // Set up skeleton
+ IBoneSetup boneSetup( &hdr, BONE_USED_BY_ANYTHING, poseparameter );
+ boneSetup.InitPose( pos, q );
+ boneSetup.AccumulatePose( pos, q, sequence, flCycle, 1.0f, t, NULL );
+
+ // Copy bones into recording logs
+ for ( bi = 0 ; bi < numbones; ++bi )
+ {
+ ((CDmeVector3Log *)poschannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), pos[ bi ] );
+ ((CDmeQuaternionLog *)rotchannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), q[ bi ] );
+ }
+ }
+}
+
+
+
+static CDmeChannelsClip *FindChannelsClipTargetingDmeGameModel( CDmeFilmClip *pClip, CDmeGameModel *pGameModel )
+{
+ uint nBoneCount = pGameModel->NumBones();
+ CDmeTransform *pGameModelTransform = pGameModel->GetTransform();
+
+ int gc = pClip->GetTrackGroupCount();
+ for ( int i = 0; i < gc; ++i )
+ {
+ CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
+ DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
+
+ if ( FindChannelTargetingElement( pChannelsClip, pGameModel ) )
+ return pChannelsClip;
+
+ if ( FindChannelTargetingElement( pChannelsClip, pGameModelTransform ) )
+ return pChannelsClip;
+
+ for ( uint j = 0; j < nBoneCount; ++j )
+ {
+ if ( FindChannelTargetingElement( pChannelsClip, pGameModel->GetBone( j ) ) )
+ return pChannelsClip;
+ }
+
+ DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
+ }
+
+ return NULL;
+}
+
+
+static void RetimeLogData( CDmeChannelsClip *pSrcChannelsClip, CDmeChannelsClip *pDstChannelsClip, CDmeLog *pLog )
+{
+ float srcScale = pSrcChannelsClip->GetTimeScale();
+ float dstScale = pDstChannelsClip->GetTimeScale();
+ DmeTime_t srcStart = pSrcChannelsClip->GetStartTime();
+ DmeTime_t dstStart = pDstChannelsClip->GetStartTime();
+ DmeTime_t srcOffset = pSrcChannelsClip->GetTimeOffset();
+ DmeTime_t dstOffset = pDstChannelsClip->GetTimeOffset();
+ srcOffset -= srcStart;
+ dstOffset -= dstStart;
+ if ( srcScale != dstScale || srcOffset != dstOffset )
+ {
+ // for speed, I pulled out the math converting out of one timeframe into another:
+ // t = (t/f0-o0+s0 -s1+o1)*f1
+ // = t * f1/f0 + f1 * (o1-o0-s1+s0)
+ float scale = dstScale / srcScale;
+ DmeTime_t offset = dstScale * ( dstOffset - srcOffset );
+ int nKeys = pLog->GetKeyCount();
+ for ( int i = 0; i < nKeys; ++i )
+ {
+ DmeTime_t keyTime = pLog->GetKeyTime( i );
+ keyTime = keyTime * scale + offset;
+ pLog->SetKeyTime( i, keyTime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Once bones have been setup and flex channels moved, the only things left should be:
+// a channel logging the model's "visibility" state
+// a channel logging the model's "sequence"
+// a channel loggint the model's "viewtarget" position
+//-----------------------------------------------------------------------------
+static void TransferRemainingChannels( CDmeFilmClip *shot, CDmeChannelsClip *destClip, CDmeChannelsClip *srcClip )
+{
+ if ( srcClip == destClip )
+ return;
+
+ int channelsCount = srcClip->m_Channels.Count();
+ for ( int i = 0; i < channelsCount; ++i )
+ {
+ // Remove channel from channels clip
+ CDmeChannel *channel = srcClip->m_Channels[ i ];
+ Assert( channel );
+ if ( !channel )
+ continue;
+
+ Msg( "Transferring '%s'\n", channel->GetName() );
+
+ destClip->m_Channels.AddToTail( channel );
+ channel->SetMode( CM_PLAY );
+
+ // Transfer the logs over to the
+ CDmeLog *log = channel->GetLog();
+ if ( log )
+ {
+ RetimeLogData( srcClip, destClip, log );
+ }
+ }
+
+ srcClip->m_Channels.RemoveAll();
+
+ // Now find the track which contains the srcClip and remove the srcClip from the track
+ for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( srcClip->GetHandle() );
+ it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
+ it = g_pDataModel->NextAttributeReferencingElement( it ) )
+ {
+ CDmAttribute *attr = g_pDataModel->GetAttribute( it );
+ Assert( attr );
+ CDmElement *element = attr->GetOwner();
+ Assert( element );
+ if ( !element )
+ continue;
+
+ CDmeTrack *t = CastElement< CDmeTrack >( element );
+ if ( !t )
+ continue;
+
+ t->RemoveClip( srcClip );
+ g_pDataModel->DestroyElement( srcClip->GetHandle() );
+ break;
+ }
+}
+
+static void SetupBoneTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip, CDmeChannelsClip *channelsClip,
+ CDmElement *control, CDmeGameModel *gameModel, const char *basename, studiohdr_t *hdr, int bonenum, const char *boneName, bool bAttachToGameRecording )
+{
+ const char *channelNames[] = { "position", "orientation" };
+ const char *valueNames[] = { "valuePosition", "valueOrientation" };
+ const char *suffix[] = { "Pos", "Rot" };
+
+ DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
+ int i;
+
+ CDmeTransform *pBoneTxForm = gameModel->GetBone( bonenum );
+
+ for ( i = 0; i < 2 ; ++i )
+ {
+ char szName[ 512 ];
+ Q_snprintf( szName, sizeof( szName ), "%s_bone%s %d", basename, suffix[ i ], bonenum );
+
+ CDmeChannel *pAttachChannel = NULL;
+ if ( srcChannelsClip )
+ {
+ pAttachChannel = FindChannelTargetingElement( srcChannelsClip, pBoneTxForm, channelNames[ i ] );
+ }
+
+ if ( !pAttachChannel )
+ {
+ // Create one
+ pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
+ Assert( pAttachChannel );
+ pAttachChannel->SetOutput( pBoneTxForm, channelNames[ i ], 0 );
+ }
+
+ if ( !pAttachChannel )
+ continue;
+
+ if ( bAttachToGameRecording && srcChannelsClip )
+ {
+ // Remove channel from channels clip
+ int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
+ if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
+ {
+ srcChannelsClip->m_Channels.Remove( idx );
+ }
+ channelsClip->m_Channels.AddToTail( pAttachChannel );
+ }
+
+ control->SetValue( channelNames[ i ], pAttachChannel );
+ control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
+
+ CDmeLog *pOriginalLog = pAttachChannel->GetLog();
+
+ pAttachChannel->SetMode( CM_PLAY );
+ pAttachChannel->SetInput( control, valueNames[ i ] );
+
+ // Transfer the logs over to the
+ if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
+ {
+ CDmeLog *pNewLog = pAttachChannel->GetLog();
+ if ( pNewLog != pOriginalLog )
+ {
+ pAttachChannel->SetLog( pOriginalLog );
+ g_pDataModel->DestroyElement( pNewLog->GetHandle() );
+ }
+
+ DmeTime_t tLogToGlobal[ 2 ];
+
+ Assert(0);
+ // NOTE: Fix the next 2 lines to look like createsfmanimation.cpp
+ DmeTime_t curtime = DMETIME_ZERO; //doc->GetTime();
+ DmeTime_t cmt = DMETIME_ZERO; //doc->ToCurrentMediaTime( curtime, false );
+ DmeTime_t channelscliptime = shot->ToChildMediaTime( cmt, false );
+
+ DmeTime_t logtime = channelsClip->ToChildMediaTime( channelscliptime, false );
+
+ tLogToGlobal[ 0 ] = curtime - logtime;
+
+ DmeTime_t attachlogtime = srcChannelsClip->ToChildMediaTime( channelscliptime, false );
+
+ tLogToGlobal[ 1 ] = curtime - attachlogtime;
+
+ DmeTime_t offset = tLogToGlobal[ 1 ] - tLogToGlobal[ 0 ];
+
+ if ( DMETIME_ZERO != offset )
+ {
+ int c = pOriginalLog->GetKeyCount();
+ for ( int iLog = 0; iLog < c; ++iLog )
+ {
+ DmeTime_t keyTime = pOriginalLog->GetKeyTime( iLog );
+ keyTime += offset;
+ pOriginalLog->SetKeyTime( iLog, keyTime );
+ }
+ }
+ continue;
+ }
+
+ if ( pOriginalLog )
+ {
+ pOriginalLog->ClearKeys();
+ }
+
+ CDmeLog *log = pAttachChannel->GetLog();
+ if ( !log )
+ {
+ log = pAttachChannel->CreateLog( channelTypes[ i ] );
+ }
+
+ log->SetValueThreshold( 0.0f );
+ if ( bAttachToGameRecording )
+ {
+ Vector pos;
+ Quaternion rot;
+
+ matrix3x4_t matrix;
+ pBoneTxForm->GetTransform( matrix );
+ MatrixAngles( matrix, rot, pos );
+
+ if ( i == 0 )
+ {
+ ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos );
+ }
+ else
+ {
+ ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, rot );
+ }
+ continue;
+ }
+
+ CStudioHdr studiohdr( hdr, g_pMDLCache );
+
+ Vector pos[ MAXSTUDIOBONES ];
+ Quaternion q[ MAXSTUDIOBONES ];
+ float poseparameter[ MAXSTUDIOPOSEPARAM ];
+ for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
+ {
+ poseparameter[ pp ] = 0.0f;
+ }
+
+ // Set up skeleton
+ IBoneSetup boneSetup( &studiohdr, BONE_USED_BY_ANYTHING, poseparameter );
+ boneSetup.InitPose( pos, q );
+ boneSetup.AccumulatePose( pos, q, 0, 0.0f, 1.0f, 0.0f, NULL );
+
+ if ( i == 0 )
+ {
+ ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos[ bonenum ] );
+ pBoneTxForm->SetPosition( pos[ bonenum ]);
+ }
+ else
+ {
+ ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, q[ bonenum ] );
+ pBoneTxForm->SetOrientation( q[ bonenum ] );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the root transform
+//-----------------------------------------------------------------------------
+static void SetupRootTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip,
+ CDmeChannelsClip *channelsClip, CDmElement *control, CDmeGameModel *gameModel, const char *basename, bool bAttachToGameRecording )
+{
+ char *channelNames[] = { "position", "orientation" };
+ char *valueNames[] = { "valuePosition", "valueOrientation" };
+ DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
+ const char *suffix[] = { "Pos", "Rot" };
+ DmAttributeType_t logType[] = { AT_VECTOR3, AT_QUATERNION };
+
+ int i;
+ for ( i = 0; i < 2 ; ++i )
+ {
+ char szName[ 512 ];
+ Q_snprintf( szName, sizeof( szName ), "%s_root%s channel", basename, suffix[ i ] );
+
+ CDmeChannel *pAttachChannel = NULL;
+ if ( srcChannelsClip )
+ {
+ pAttachChannel = FindChannelTargetingElement( srcChannelsClip, gameModel->GetTransform(), channelNames[ i ] );
+ }
+
+ if ( !pAttachChannel )
+ {
+ // Create one
+ pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
+ Assert( pAttachChannel );
+ pAttachChannel->SetOutput( gameModel->GetTransform(), channelNames[ i ], 0 );
+ }
+
+ if ( bAttachToGameRecording && srcChannelsClip )
+ {
+ // Remove channel from channels clip
+ int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
+ if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
+ {
+ srcChannelsClip->m_Channels.Remove( idx );
+ }
+ channelsClip->m_Channels.AddToTail( pAttachChannel );
+ }
+
+ control->SetValue( channelNames[ i ], pAttachChannel );
+ control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
+
+ CDmeLog *pOriginalLog = pAttachChannel->GetLog();
+
+ pAttachChannel->SetMode( CM_PLAY );
+ pAttachChannel->SetInput( control, valueNames[ i ] );
+
+ if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
+ {
+ CDmeLog *pNewLog = pAttachChannel->GetLog();
+ if ( pNewLog != pOriginalLog )
+ {
+ pAttachChannel->SetLog( pOriginalLog );
+ g_pDataModel->DestroyElement( pNewLog->GetHandle() );
+ }
+
+ RetimeLogData( srcChannelsClip, channelsClip, pOriginalLog );
+ }
+ else
+ {
+ Assert( !pOriginalLog );
+ CDmeLog *log = pAttachChannel->GetLog();
+ if ( !log )
+ {
+ log = pAttachChannel->CreateLog( logType[ i ] );
+ }
+
+ log->SetValueThreshold( 0.0f );
+
+ Vector vecPos;
+ Quaternion qOrientation;
+
+ matrix3x4_t txform;
+ gameModel->GetTransform()->GetTransform( txform );
+
+ MatrixAngles( txform, qOrientation, vecPos );
+
+ if ( i == 0 )
+ {
+ ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, vecPos );
+ }
+ else
+ {
+ ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, qOrientation );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates preset groups for new animation sets
+//-----------------------------------------------------------------------------
+static bool ShouldRandomize( const char *name )
+{
+ if ( !Q_stricmp( name, "eyes_updown" ) )
+ return false;
+ if ( !Q_stricmp( name, "eyes_rightleft" ) )
+ return false;
+ if ( !Q_stricmp( name, "lip_bite" ) )
+ return false;
+ if ( !Q_stricmp( name, "blink" ) )
+ return false;
+ if ( Q_stristr( name, "sneer" ) )
+ return false;
+ return true;
+}
+
+static void CreateProceduralPreset( CDmePresetGroup *pPresetGroup, const char *pPresetName, const CDmaElementArray< CDmElement > &controls, bool bIdentity, float flForceValue = 0.5f )
+{
+ CDmePreset *pPreset = pPresetGroup->FindOrAddPreset( pPresetName );
+
+ int c = controls.Count();
+ for ( int i = 0; i < c ; ++i )
+ {
+ CDmElement *pControl = controls[ i ];
+
+ // Setting values on transforms doesn't make sense right now
+ if ( pControl->GetValue<bool>( "transform" ) )
+ continue;
+
+ bool bIsCombo = pControl->GetValue< bool >( "combo" );
+ bool bIsMulti = pControl->GetValue< bool >( "multi" );
+ bool bRandomize = ShouldRandomize( pControl->GetName() );
+ if ( !bIdentity && !bRandomize )
+ continue;
+
+ CDmElement *pControlValue = pPreset->FindOrAddControlValue( pControl->GetName() );
+
+ if ( !bIdentity )
+ {
+ pControlValue->SetValue< float >( "value", RandomFloat( 0.0f, 1.0f ) );
+ if ( bIsCombo )
+ {
+ pControlValue->SetValue< float >( "balance", RandomFloat( 0.25f, 0.75f ) );
+ }
+ if ( bIsMulti )
+ {
+ pControlValue->SetValue< float >( "multilevel", RandomFloat( 0.0f, 1.0f ) );
+ }
+ }
+ else
+ {
+ pControlValue->SetValue< float >( "value", flForceValue );
+ if ( bIsCombo )
+ {
+ pControlValue->SetValue< float >( "balance", 0.5f );
+ }
+ if ( bIsMulti )
+ {
+ pControlValue->SetValue< float >( "multilevel", flForceValue );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates preset groups for new animation sets
+//-----------------------------------------------------------------------------
+static void CreatePresetGroups( CDmeAnimationSet *pAnimationSet, const char *pModelName )
+{
+ CDmaElementArray< CDmElement > &controls = pAnimationSet->GetControls();
+
+ // Now create some presets
+ CDmePresetGroup *pProceduralPresets = pAnimationSet->FindOrAddPresetGroup( "procedural" );
+ pProceduralPresets->m_bIsReadOnly = true;
+ pProceduralPresets->FindOrAddPreset( "Default" );
+ CreateProceduralPreset( pProceduralPresets, "Zero", controls, true, 0.0f );
+ CreateProceduralPreset( pProceduralPresets, "Half", controls, true, 0.5f );
+ CreateProceduralPreset( pProceduralPresets, "One", controls, true, 1.0f );
+
+ // Add just one fake one for now
+ CreateProceduralPreset( pProceduralPresets, "Random", controls, false );
+
+ // These are the truly procedural ones...
+ pAnimationSet->EnsureProceduralPresets();
+
+ // Also load the model-specific presets
+ g_pModelPresetGroupMgr->ApplyModelPresets( pModelName, pAnimationSet );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys existing group mappings
+//-----------------------------------------------------------------------------
+static void RemoveExistingGroupMappings( CDmeAnimationSet *pAnimationSet )
+{
+ CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
+ int nCount = groups.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmElement *pGroup = groups[i];
+ groups.Set( i, NULL );
+ DestroyElement( pGroup );
+ }
+ groups.RemoveAll();
+}
+
+
+void LoadDefaultGroupMappings( CUtlDict< CUtlString, int > &defaultGroupMapping, CUtlVector< CUtlString >& defaultGroupOrdering )
+{
+ defaultGroupMapping.RemoveAll();
+ defaultGroupOrdering.RemoveAll();
+
+ KeyValues *pGroupFile = new KeyValues( "groupFile" );
+ if ( !pGroupFile )
+ return;
+
+ if ( !pGroupFile->LoadFromFile( g_pFullFileSystem, ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE, "GAME" ) )
+ {
+ pGroupFile->deleteThis();
+ return;
+ }
+
+ // Fill in defaults
+ for ( KeyValues *sub = pGroupFile->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
+ {
+ const char *pGroupName = sub->GetName();
+ if ( !pGroupName )
+ {
+ Warning( "%s is malformed\n", ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE );
+ continue;
+ }
+
+ int i = defaultGroupOrdering.AddToTail();
+ defaultGroupOrdering[i] = pGroupName;
+
+ for ( KeyValues *pControl = sub->GetFirstSubKey(); pControl; pControl = pControl->GetNextKey() )
+ {
+ Assert( !Q_stricmp( pControl->GetName(), "control" ) );
+ CUtlString controlName = pControl->GetString();
+ defaultGroupMapping.Insert( controlName, pGroupName );
+ }
+ }
+
+ pGroupFile->deleteThis();
+}
+
+CDmElement *FindOrAddDefaultGroupForControls( const char *pGroupName, CDmaElementArray< CDmElement > &groups, DmFileId_t fileid )
+{
+ // Now see if this group exists in the array
+ int c = groups.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ CDmElement *pGroup = groups[ i ];
+ if ( !Q_stricmp( pGroup->GetName(), pGroupName ) )
+ return pGroup;
+ }
+
+ CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, fileid );
+ pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
+ groups.AddToTail( pGroup );
+ return pGroup;
+}
+
+//-----------------------------------------------------------------------------
+// Build group mappings
+//-----------------------------------------------------------------------------
+static void BuildGroupMappings( CDmeAnimationSet *pAnimationSet )
+{
+ RemoveExistingGroupMappings( pAnimationSet );
+
+ // Maps flex controls to first level "groups" by flex controller name
+ CUtlDict< CUtlString, int > defaultGroupMapping;
+ CUtlVector< CUtlString > defaultGroupOrdering;
+
+ LoadDefaultGroupMappings( defaultGroupMapping, defaultGroupOrdering );
+
+ // Create the default groups in order
+ CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
+ int nCount = defaultGroupOrdering.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const char *pGroupName = (const char *)defaultGroupOrdering[ i ];
+ if ( !Q_stricmp( pGroupName, "IGNORE" ) )
+ continue;
+
+ CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, pAnimationSet->GetFileId() );
+
+ // Fill in members
+ pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
+ groups.AddToTail( pGroup );
+ }
+
+ // Populate the groups with the controls
+ CDmaElementArray<> &controls = pAnimationSet->GetControls();
+ nCount = controls.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const char *pGroupName = "Unknown";
+ const char *pControlName = controls[ i ]->GetName();
+
+ // Find the default if there is one
+ int idx = defaultGroupMapping.Find( pControlName );
+ if ( idx != defaultGroupMapping.InvalidIndex() )
+ {
+ pGroupName = defaultGroupMapping[ idx ];
+ }
+ else if ( Q_stristr( pControlName, "root" ) || Q_stristr( pControlName, "Valve" ) )
+ {
+ pGroupName = "Root";
+ }
+
+ if ( !Q_stricmp( pGroupName, "IGNORE" ) )
+ continue;
+
+ CDmElement *pGroup = FindOrAddDefaultGroupForControls( pGroupName, groups, pAnimationSet->GetFileId() );
+
+ // Fill in members
+ CDmrStringArray selectedControls( pGroup, "selectedControls" );
+ Assert( selectedControls.IsValid() );
+ if ( selectedControls.IsValid() )
+ {
+ selectedControls.AddToTail( pControlName );
+ }
+ }
+}
+
+void AddIllumPositionAttribute( CDmeGameModel *pGameModel )
+{
+ studiohdr_t *pHdr = pGameModel->GetStudioHdr();
+ if ( !pHdr )
+ return;
+
+ if ( pHdr->IllumPositionAttachmentIndex() > 0 )
+ return; // don't add attr if model already has illumposition attachment
+
+ CDmAttribute *pAttr = pGameModel->AddAttributeElement< CDmeDag >( "illumPositionDag" );
+ Assert( pAttr );
+ if ( !pAttr )
+ return;
+
+ Assert( pGameModel->GetChildCount() > 0 );
+ pAttr->SetValue( pGameModel->GetChild( 0 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Creates an animation set
+//-----------------------------------------------------------------------------
+CDmeAnimationSet *CreateAnimationSet( CDmeFilmClip *pMovie, CDmeFilmClip *pShot,
+ CDmeGameModel *pGameModel, const char *pAnimationSetName, int nSequenceToUse, bool bAttachToGameRecording )
+{
+ CDmeAnimationSet *pAnimationSet = CreateElement< CDmeAnimationSet >( pAnimationSetName, pMovie->GetFileId() );
+ Assert( pAnimationSet );
+
+ studiohdr_t *hdr = pGameModel->GetStudioHdr();
+
+ // Associate this animation set with a specific game model
+ // FIXME: Should the game model refer back to this set?
+ pAnimationSet->SetValue( "gameModel", pGameModel );
+
+ CDmeChannelsClip* pChannelsClip = CreateChannelsClip( pAnimationSet, pShot );
+
+ // Does everything associated with building facial controls on a model
+ CFlexControlBuilder builder;
+ builder.CreateAnimationSetControls( pMovie, pAnimationSet, pGameModel, pShot, pChannelsClip, bAttachToGameRecording );
+
+ // Create animation data if there wasn't any already in the model
+ if ( !bAttachToGameRecording )
+ {
+ CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "skin", pGameModel, "skin", (int)0 );
+ CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "body", pGameModel, "body", (int)0 );
+ CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "sequence", pGameModel, "sequence", (int)0 );
+
+ CreateAnimationLogs( pChannelsClip, pGameModel, hdr, pAnimationSetName, nSequenceToUse, 0.0f, 1.0f, 0.05f );
+ }
+
+ CDmeChannelsClip *srcChannelsClip = FindChannelsClipTargetingDmeGameModel( pShot, pGameModel );
+ CDmaElementArray<> &controls = pAnimationSet->GetControls();
+
+ // First the root transform
+ {
+ const char *ctrlName = "rootTransform";
+
+ // Add the control to the controls group
+ CDmElement *ctrl = CreateElement< CDmElement >( ctrlName, pMovie->GetFileId() );
+ Assert( ctrl );
+ ctrl->SetValue< bool >( "transform", true );
+ controls.AddToTail( ctrl );
+ SetupRootTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, bAttachToGameRecording );
+ }
+
+ // Now add the bone transforms as well
+ {
+ int numbones = hdr->numbones;
+ for ( int b = 0; b < numbones; ++b )
+ {
+ mstudiobone_t *bone = hdr->pBone( b );
+ const char *name = bone->pszName();
+
+ // Add the control to the controls group
+ CDmElement *ctrl = CreateElement< CDmElement >( name, pMovie->GetFileId() );
+ Assert( ctrl );
+ ctrl->SetValue< bool >( "transform", true );
+ controls.AddToTail( ctrl );
+ SetupBoneTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, hdr, b, name, bAttachToGameRecording );
+ }
+ }
+
+ // Now copy all remaining logs, and retime them, over to the animation set channels clip...
+ if ( srcChannelsClip )
+ {
+ TransferRemainingChannels( pShot, pChannelsClip, srcChannelsClip );
+ }
+
+ // Create default preset groups for the animation set
+ CreatePresetGroups( pAnimationSet, pGameModel->GetModelName() );
+
+ // Builds the preset groups displayed in the upper left of the animation set panel
+ BuildGroupMappings( pAnimationSet );
+
+ pShot->AddAnimationSet( pAnimationSet );
+
+ AddIllumPositionAttribute( pGameModel );
+
+ return pAnimationSet;
+}