Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

891 lines
28 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // NOTE: This is a cut-and-paste hack job to get animation set construction
  4. // working from a commandline tool. It came from tools/ifm/createsfmanimation.cpp
  5. // This file needs to die almost immediately + be replaced with a better solution
  6. // that can be used both by the sfm + sfmgen.
  7. //
  8. //=============================================================================
  9. #include "sfmobjects/sfmanimationsetutils.h"
  10. #include "movieobjects/dmechannel.h"
  11. #include "movieobjects/dmeclip.h"
  12. #include "movieobjects/dmetrackgroup.h"
  13. #include "movieobjects/dmetrack.h"
  14. #include "movieobjects/dmecamera.h"
  15. #include "movieobjects/dmetimeselection.h"
  16. #include "movieobjects/dmeanimationset.h"
  17. #include "movieobjects/dmegamemodel.h"
  18. #include "sfmobjects/flexcontrolbuilder.h"
  19. #include "tier3/tier3.h"
  20. #include "bone_setup.h"
  21. #include "vstdlib/random.h"
  22. #include "tier1/KeyValues.h"
  23. #include "filesystem.h"
  24. #include "movieobjects/timeutils.h"
  25. #define ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE "cfg/SFM_DefaultAnimationGroups.txt"
  26. #define STANDARD_CHANNEL_TRACK_GROUP "channelTrackGroup"
  27. #define STANDARD_ANIMATIONSET_CHANNELS_TRACK "animSetEditorChannels"
  28. #define CLIP_PREROLL_TIME DmeTime_t( 5.0f )
  29. #define CLIP_POSTROLL_TIME DmeTime_t( 5.0f )
  30. //-----------------------------------------------------------------------------
  31. // Creates channels clip for the animation set
  32. //-----------------------------------------------------------------------------
  33. static CDmeChannelsClip* CreateChannelsClip( CDmeAnimationSet *pAnimationSet, CDmeFilmClip *pOwnerClip )
  34. {
  35. CDmeTrackGroup *pTrackGroup = pOwnerClip->FindOrAddTrackGroup( "channelTrackGroup" );
  36. if ( !pTrackGroup )
  37. {
  38. Assert( 0 );
  39. return NULL;
  40. }
  41. CDmeTrack *pAnimSetEditorTrack = pTrackGroup->FindOrAddTrack( "animSetEditorChannels", DMECLIP_CHANNEL );
  42. Assert( pAnimSetEditorTrack );
  43. CDmeChannelsClip *pChannelsClip = CreateElement< CDmeChannelsClip >( pAnimationSet->GetName(), pAnimationSet->GetFileId() );
  44. pAnimSetEditorTrack->AddClip( pChannelsClip );
  45. DmeTime_t childMediaTime = pOwnerClip->GetStartInChildMediaTime();
  46. pChannelsClip->SetStartTime( childMediaTime - CLIP_PREROLL_TIME );
  47. DmeTime_t childMediaDuration = pOwnerClip->ToChildMediaDuration( pOwnerClip->GetDuration() );
  48. pChannelsClip->SetDuration( childMediaDuration + CLIP_PREROLL_TIME + CLIP_POSTROLL_TIME );
  49. return pChannelsClip;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Creates a constant valued log
  53. //-----------------------------------------------------------------------------
  54. template < class T >
  55. CDmeChannel *CreateConstantValuedLog( CDmeChannelsClip *channelsClip, const char *basename, const char *pName, CDmElement *pToElement, const char *pToAttr, const T &value )
  56. {
  57. char name[ 256 ];
  58. Q_snprintf( name, sizeof( name ), "%s_%s channel", basename, pName );
  59. CDmeChannel *pChannel = CreateElement< CDmeChannel >( name, channelsClip->GetFileId() );
  60. pChannel->SetMode( CM_PLAY );
  61. pChannel->CreateLog( CDmAttributeInfo< T >::AttributeType() );
  62. pChannel->SetOutput( pToElement, pToAttr );
  63. pChannel->GetLog()->SetValueThreshold( 0.0f );
  64. ((CDmeTypedLog< T > *)pChannel->GetLog())->InsertKey( DmeTime_t( 0 ), value );
  65. channelsClip->m_Channels.AddToTail( pChannel );
  66. return pChannel;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Create channels for transform data
  70. //-----------------------------------------------------------------------------
  71. static void CreateTransformChannels( CDmeTransform *pTransform, const char *pBaseName, int bi, CDmeChannelsClip *pChannelsClip )
  72. {
  73. char name[ 256 ];
  74. // create, connect and cache bonePos channel
  75. Q_snprintf( name, sizeof( name ), "%s_bonePos channel %d", pBaseName, bi );
  76. CDmeChannel *pPosChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
  77. pPosChannel->SetMode( CM_PLAY );
  78. pPosChannel->CreateLog( AT_VECTOR3 );
  79. pPosChannel->SetOutput( pTransform, "position" );
  80. pPosChannel->GetLog()->SetValueThreshold( 0.0f );
  81. pChannelsClip->m_Channels.AddToTail( pPosChannel );
  82. // create, connect and cache boneRot channel
  83. Q_snprintf( name, sizeof( name ), "%s_boneRot channel %d", pBaseName, bi );
  84. CDmeChannel *pRotChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
  85. pRotChannel->SetMode( CM_PLAY );
  86. pRotChannel->CreateLog( AT_QUATERNION );
  87. pRotChannel->SetOutput( pTransform, "orientation" );
  88. pRotChannel->GetLog()->SetValueThreshold( 0.0f );
  89. pChannelsClip->m_Channels.AddToTail( pRotChannel );
  90. }
  91. static void CreateAnimationLogs( CDmeChannelsClip *channelsClip, CDmeGameModel *pModel, studiohdr_t *pStudioHdr, const char *basename, int sequence, float flStartTime, float flDuration, float flTimeStep = 0.015f )
  92. {
  93. Assert( pModel );
  94. Assert( pStudioHdr );
  95. CStudioHdr hdr( pStudioHdr, g_pMDLCache );
  96. if ( sequence >= hdr.GetNumSeq() )
  97. {
  98. sequence = 0;
  99. }
  100. int numbones = hdr.numbones();
  101. // make room for bones
  102. CUtlVector< CDmeDag* > dags;
  103. CUtlVector< CDmeChannel * > poschannels;
  104. CUtlVector< CDmeChannel * > rotchannels;
  105. dags.EnsureCapacity( numbones );
  106. poschannels.EnsureCapacity( numbones );
  107. rotchannels.EnsureCapacity( numbones );
  108. Vector pos[ MAXSTUDIOBONES ];
  109. Quaternion q[ MAXSTUDIOBONES ];
  110. float poseparameter[ MAXSTUDIOPOSEPARAM ];
  111. for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
  112. {
  113. poseparameter[ pp ] = 0.0f;
  114. }
  115. float flSequenceDuration = Studio_Duration( &hdr, sequence, poseparameter );
  116. mstudioseqdesc_t &seqdesc = hdr.pSeqdesc( sequence );
  117. bool created = false;
  118. for ( float t = flStartTime; t <= flStartTime + flDuration; t += flTimeStep )
  119. {
  120. int bi;
  121. if ( t > flStartTime + flDuration )
  122. t = flStartTime + flDuration;
  123. float flCycle = t / flSequenceDuration;
  124. if ( seqdesc.flags & STUDIO_LOOPING )
  125. {
  126. flCycle = flCycle - (int)flCycle;
  127. if (flCycle < 0) flCycle += 1;
  128. }
  129. else
  130. {
  131. flCycle = max( 0.f, min( flCycle, 0.9999f ) );
  132. }
  133. if ( !created )
  134. {
  135. created = true;
  136. // create, connect and cache each bone's pos and rot channels
  137. for ( bi = 0; bi < numbones; ++bi )
  138. {
  139. int nCount = channelsClip->m_Channels.Count();
  140. CDmeTransform *pTransform = pModel->GetBone( bi );
  141. CreateTransformChannels( pTransform, basename, bi, channelsClip );
  142. CDmeChannel *pPosChannel = channelsClip->m_Channels[ nCount ];
  143. CDmeChannel *pRotChannel = channelsClip->m_Channels[ nCount+1 ];
  144. poschannels.AddToTail( pPosChannel );
  145. rotchannels.AddToTail( pRotChannel );
  146. }
  147. }
  148. // Set up skeleton
  149. IBoneSetup boneSetup( &hdr, BONE_USED_BY_ANYTHING, poseparameter );
  150. boneSetup.InitPose( pos, q );
  151. boneSetup.AccumulatePose( pos, q, sequence, flCycle, 1.0f, t, NULL );
  152. // Copy bones into recording logs
  153. for ( bi = 0 ; bi < numbones; ++bi )
  154. {
  155. ((CDmeVector3Log *)poschannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), pos[ bi ] );
  156. ((CDmeQuaternionLog *)rotchannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), q[ bi ] );
  157. }
  158. }
  159. }
  160. static CDmeChannelsClip *FindChannelsClipTargetingDmeGameModel( CDmeFilmClip *pClip, CDmeGameModel *pGameModel )
  161. {
  162. uint nBoneCount = pGameModel->NumBones();
  163. CDmeTransform *pGameModelTransform = pGameModel->GetTransform();
  164. int gc = pClip->GetTrackGroupCount();
  165. for ( int i = 0; i < gc; ++i )
  166. {
  167. CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
  168. DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
  169. if ( FindChannelTargetingElement( pChannelsClip, pGameModel ) )
  170. return pChannelsClip;
  171. if ( FindChannelTargetingElement( pChannelsClip, pGameModelTransform ) )
  172. return pChannelsClip;
  173. for ( uint j = 0; j < nBoneCount; ++j )
  174. {
  175. if ( FindChannelTargetingElement( pChannelsClip, pGameModel->GetBone( j ) ) )
  176. return pChannelsClip;
  177. }
  178. DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
  179. }
  180. return NULL;
  181. }
  182. static void RetimeLogData( CDmeChannelsClip *pSrcChannelsClip, CDmeChannelsClip *pDstChannelsClip, CDmeLog *pLog )
  183. {
  184. float srcScale = pSrcChannelsClip->GetTimeScale();
  185. float dstScale = pDstChannelsClip->GetTimeScale();
  186. DmeTime_t srcStart = pSrcChannelsClip->GetStartTime();
  187. DmeTime_t dstStart = pDstChannelsClip->GetStartTime();
  188. DmeTime_t srcOffset = pSrcChannelsClip->GetTimeOffset();
  189. DmeTime_t dstOffset = pDstChannelsClip->GetTimeOffset();
  190. srcOffset -= srcStart;
  191. dstOffset -= dstStart;
  192. if ( srcScale != dstScale || srcOffset != dstOffset )
  193. {
  194. // for speed, I pulled out the math converting out of one timeframe into another:
  195. // t = (t/f0-o0+s0 -s1+o1)*f1
  196. // = t * f1/f0 + f1 * (o1-o0-s1+s0)
  197. float scale = dstScale / srcScale;
  198. DmeTime_t offset = dstScale * ( dstOffset - srcOffset );
  199. int nKeys = pLog->GetKeyCount();
  200. for ( int i = 0; i < nKeys; ++i )
  201. {
  202. DmeTime_t keyTime = pLog->GetKeyTime( i );
  203. keyTime = keyTime * scale + offset;
  204. pLog->SetKeyTime( i, keyTime );
  205. }
  206. }
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose: Once bones have been setup and flex channels moved, the only things left should be:
  210. // a channel logging the model's "visibility" state
  211. // a channel logging the model's "sequence"
  212. // a channel loggint the model's "viewtarget" position
  213. //-----------------------------------------------------------------------------
  214. static void TransferRemainingChannels( CDmeFilmClip *shot, CDmeChannelsClip *destClip, CDmeChannelsClip *srcClip )
  215. {
  216. if ( srcClip == destClip )
  217. return;
  218. int channelsCount = srcClip->m_Channels.Count();
  219. for ( int i = 0; i < channelsCount; ++i )
  220. {
  221. // Remove channel from channels clip
  222. CDmeChannel *channel = srcClip->m_Channels[ i ];
  223. Assert( channel );
  224. if ( !channel )
  225. continue;
  226. Msg( "Transferring '%s'\n", channel->GetName() );
  227. destClip->m_Channels.AddToTail( channel );
  228. channel->SetMode( CM_PLAY );
  229. // Transfer the logs over to the
  230. CDmeLog *log = channel->GetLog();
  231. if ( log )
  232. {
  233. RetimeLogData( srcClip, destClip, log );
  234. }
  235. }
  236. srcClip->m_Channels.RemoveAll();
  237. // Now find the track which contains the srcClip and remove the srcClip from the track
  238. for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( srcClip->GetHandle() );
  239. it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
  240. it = g_pDataModel->NextAttributeReferencingElement( it ) )
  241. {
  242. CDmAttribute *attr = g_pDataModel->GetAttribute( it );
  243. Assert( attr );
  244. CDmElement *element = attr->GetOwner();
  245. Assert( element );
  246. if ( !element )
  247. continue;
  248. CDmeTrack *t = CastElement< CDmeTrack >( element );
  249. if ( !t )
  250. continue;
  251. t->RemoveClip( srcClip );
  252. g_pDataModel->DestroyElement( srcClip->GetHandle() );
  253. break;
  254. }
  255. }
  256. static void SetupBoneTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip, CDmeChannelsClip *channelsClip,
  257. CDmElement *control, CDmeGameModel *gameModel, const char *basename, studiohdr_t *hdr, int bonenum, const char *boneName, bool bAttachToGameRecording )
  258. {
  259. const char *channelNames[] = { "position", "orientation" };
  260. const char *valueNames[] = { "valuePosition", "valueOrientation" };
  261. const char *suffix[] = { "Pos", "Rot" };
  262. DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
  263. int i;
  264. CDmeTransform *pBoneTxForm = gameModel->GetBone( bonenum );
  265. for ( i = 0; i < 2 ; ++i )
  266. {
  267. char szName[ 512 ];
  268. Q_snprintf( szName, sizeof( szName ), "%s_bone%s %d", basename, suffix[ i ], bonenum );
  269. CDmeChannel *pAttachChannel = NULL;
  270. if ( srcChannelsClip )
  271. {
  272. pAttachChannel = FindChannelTargetingElement( srcChannelsClip, pBoneTxForm, channelNames[ i ] );
  273. }
  274. if ( !pAttachChannel )
  275. {
  276. // Create one
  277. pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
  278. Assert( pAttachChannel );
  279. pAttachChannel->SetOutput( pBoneTxForm, channelNames[ i ], 0 );
  280. }
  281. if ( !pAttachChannel )
  282. continue;
  283. if ( bAttachToGameRecording && srcChannelsClip )
  284. {
  285. // Remove channel from channels clip
  286. int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
  287. if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
  288. {
  289. srcChannelsClip->m_Channels.Remove( idx );
  290. }
  291. channelsClip->m_Channels.AddToTail( pAttachChannel );
  292. }
  293. control->SetValue( channelNames[ i ], pAttachChannel );
  294. control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
  295. CDmeLog *pOriginalLog = pAttachChannel->GetLog();
  296. pAttachChannel->SetMode( CM_PLAY );
  297. pAttachChannel->SetInput( control, valueNames[ i ] );
  298. // Transfer the logs over to the
  299. if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
  300. {
  301. CDmeLog *pNewLog = pAttachChannel->GetLog();
  302. if ( pNewLog != pOriginalLog )
  303. {
  304. pAttachChannel->SetLog( pOriginalLog );
  305. g_pDataModel->DestroyElement( pNewLog->GetHandle() );
  306. }
  307. DmeTime_t tLogToGlobal[ 2 ];
  308. Assert(0);
  309. // NOTE: Fix the next 2 lines to look like createsfmanimation.cpp
  310. DmeTime_t curtime = DMETIME_ZERO; //doc->GetTime();
  311. DmeTime_t cmt = DMETIME_ZERO; //doc->ToCurrentMediaTime( curtime, false );
  312. DmeTime_t channelscliptime = shot->ToChildMediaTime( cmt, false );
  313. DmeTime_t logtime = channelsClip->ToChildMediaTime( channelscliptime, false );
  314. tLogToGlobal[ 0 ] = curtime - logtime;
  315. DmeTime_t attachlogtime = srcChannelsClip->ToChildMediaTime( channelscliptime, false );
  316. tLogToGlobal[ 1 ] = curtime - attachlogtime;
  317. DmeTime_t offset = tLogToGlobal[ 1 ] - tLogToGlobal[ 0 ];
  318. if ( DMETIME_ZERO != offset )
  319. {
  320. int c = pOriginalLog->GetKeyCount();
  321. for ( int iLog = 0; iLog < c; ++iLog )
  322. {
  323. DmeTime_t keyTime = pOriginalLog->GetKeyTime( iLog );
  324. keyTime += offset;
  325. pOriginalLog->SetKeyTime( iLog, keyTime );
  326. }
  327. }
  328. continue;
  329. }
  330. if ( pOriginalLog )
  331. {
  332. pOriginalLog->ClearKeys();
  333. }
  334. CDmeLog *log = pAttachChannel->GetLog();
  335. if ( !log )
  336. {
  337. log = pAttachChannel->CreateLog( channelTypes[ i ] );
  338. }
  339. log->SetValueThreshold( 0.0f );
  340. if ( bAttachToGameRecording )
  341. {
  342. Vector pos;
  343. Quaternion rot;
  344. matrix3x4_t matrix;
  345. pBoneTxForm->GetTransform( matrix );
  346. MatrixAngles( matrix, rot, pos );
  347. if ( i == 0 )
  348. {
  349. ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos );
  350. }
  351. else
  352. {
  353. ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, rot );
  354. }
  355. continue;
  356. }
  357. CStudioHdr studiohdr( hdr, g_pMDLCache );
  358. Vector pos[ MAXSTUDIOBONES ];
  359. Quaternion q[ MAXSTUDIOBONES ];
  360. float poseparameter[ MAXSTUDIOPOSEPARAM ];
  361. for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
  362. {
  363. poseparameter[ pp ] = 0.0f;
  364. }
  365. // Set up skeleton
  366. IBoneSetup boneSetup( &studiohdr, BONE_USED_BY_ANYTHING, poseparameter );
  367. boneSetup.InitPose( pos, q );
  368. boneSetup.AccumulatePose( pos, q, 0, 0.0f, 1.0f, 0.0f, NULL );
  369. if ( i == 0 )
  370. {
  371. ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos[ bonenum ] );
  372. pBoneTxForm->SetPosition( pos[ bonenum ]);
  373. }
  374. else
  375. {
  376. ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, q[ bonenum ] );
  377. pBoneTxForm->SetOrientation( q[ bonenum ] );
  378. }
  379. }
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Sets up the root transform
  383. //-----------------------------------------------------------------------------
  384. static void SetupRootTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip,
  385. CDmeChannelsClip *channelsClip, CDmElement *control, CDmeGameModel *gameModel, const char *basename, bool bAttachToGameRecording )
  386. {
  387. char *channelNames[] = { "position", "orientation" };
  388. char *valueNames[] = { "valuePosition", "valueOrientation" };
  389. DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
  390. const char *suffix[] = { "Pos", "Rot" };
  391. DmAttributeType_t logType[] = { AT_VECTOR3, AT_QUATERNION };
  392. int i;
  393. for ( i = 0; i < 2 ; ++i )
  394. {
  395. char szName[ 512 ];
  396. Q_snprintf( szName, sizeof( szName ), "%s_root%s channel", basename, suffix[ i ] );
  397. CDmeChannel *pAttachChannel = NULL;
  398. if ( srcChannelsClip )
  399. {
  400. pAttachChannel = FindChannelTargetingElement( srcChannelsClip, gameModel->GetTransform(), channelNames[ i ] );
  401. }
  402. if ( !pAttachChannel )
  403. {
  404. // Create one
  405. pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
  406. Assert( pAttachChannel );
  407. pAttachChannel->SetOutput( gameModel->GetTransform(), channelNames[ i ], 0 );
  408. }
  409. if ( bAttachToGameRecording && srcChannelsClip )
  410. {
  411. // Remove channel from channels clip
  412. int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
  413. if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
  414. {
  415. srcChannelsClip->m_Channels.Remove( idx );
  416. }
  417. channelsClip->m_Channels.AddToTail( pAttachChannel );
  418. }
  419. control->SetValue( channelNames[ i ], pAttachChannel );
  420. control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
  421. CDmeLog *pOriginalLog = pAttachChannel->GetLog();
  422. pAttachChannel->SetMode( CM_PLAY );
  423. pAttachChannel->SetInput( control, valueNames[ i ] );
  424. if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
  425. {
  426. CDmeLog *pNewLog = pAttachChannel->GetLog();
  427. if ( pNewLog != pOriginalLog )
  428. {
  429. pAttachChannel->SetLog( pOriginalLog );
  430. g_pDataModel->DestroyElement( pNewLog->GetHandle() );
  431. }
  432. RetimeLogData( srcChannelsClip, channelsClip, pOriginalLog );
  433. }
  434. else
  435. {
  436. Assert( !pOriginalLog );
  437. CDmeLog *log = pAttachChannel->GetLog();
  438. if ( !log )
  439. {
  440. log = pAttachChannel->CreateLog( logType[ i ] );
  441. }
  442. log->SetValueThreshold( 0.0f );
  443. Vector vecPos;
  444. Quaternion qOrientation;
  445. matrix3x4_t txform;
  446. gameModel->GetTransform()->GetTransform( txform );
  447. MatrixAngles( txform, qOrientation, vecPos );
  448. if ( i == 0 )
  449. {
  450. ((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, vecPos );
  451. }
  452. else
  453. {
  454. ((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, qOrientation );
  455. }
  456. }
  457. }
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Creates preset groups for new animation sets
  461. //-----------------------------------------------------------------------------
  462. static bool ShouldRandomize( const char *name )
  463. {
  464. if ( !Q_stricmp( name, "eyes_updown" ) )
  465. return false;
  466. if ( !Q_stricmp( name, "eyes_rightleft" ) )
  467. return false;
  468. if ( !Q_stricmp( name, "lip_bite" ) )
  469. return false;
  470. if ( !Q_stricmp( name, "blink" ) )
  471. return false;
  472. if ( Q_stristr( name, "sneer" ) )
  473. return false;
  474. return true;
  475. }
  476. static void CreateProceduralPreset( CDmePresetGroup *pPresetGroup, const char *pPresetName, const CDmaElementArray< CDmElement > &controls, bool bIdentity, float flForceValue = 0.5f )
  477. {
  478. CDmePreset *pPreset = pPresetGroup->FindOrAddPreset( pPresetName );
  479. int c = controls.Count();
  480. for ( int i = 0; i < c ; ++i )
  481. {
  482. CDmElement *pControl = controls[ i ];
  483. // Setting values on transforms doesn't make sense right now
  484. if ( pControl->GetValue<bool>( "transform" ) )
  485. continue;
  486. bool bIsCombo = pControl->GetValue< bool >( "combo" );
  487. bool bIsMulti = pControl->GetValue< bool >( "multi" );
  488. bool bRandomize = ShouldRandomize( pControl->GetName() );
  489. if ( !bIdentity && !bRandomize )
  490. continue;
  491. CDmElement *pControlValue = pPreset->FindOrAddControlValue( pControl->GetName() );
  492. if ( !bIdentity )
  493. {
  494. pControlValue->SetValue< float >( "value", RandomFloat( 0.0f, 1.0f ) );
  495. if ( bIsCombo )
  496. {
  497. pControlValue->SetValue< float >( "balance", RandomFloat( 0.25f, 0.75f ) );
  498. }
  499. if ( bIsMulti )
  500. {
  501. pControlValue->SetValue< float >( "multilevel", RandomFloat( 0.0f, 1.0f ) );
  502. }
  503. }
  504. else
  505. {
  506. pControlValue->SetValue< float >( "value", flForceValue );
  507. if ( bIsCombo )
  508. {
  509. pControlValue->SetValue< float >( "balance", 0.5f );
  510. }
  511. if ( bIsMulti )
  512. {
  513. pControlValue->SetValue< float >( "multilevel", flForceValue );
  514. }
  515. }
  516. }
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Creates preset groups for new animation sets
  520. //-----------------------------------------------------------------------------
  521. static void CreatePresetGroups( CDmeAnimationSet *pAnimationSet, const char *pModelName )
  522. {
  523. CDmaElementArray< CDmElement > &controls = pAnimationSet->GetControls();
  524. // Now create some presets
  525. CDmePresetGroup *pProceduralPresets = pAnimationSet->FindOrAddPresetGroup( "procedural" );
  526. pProceduralPresets->m_bIsReadOnly = true;
  527. pProceduralPresets->FindOrAddPreset( "Default" );
  528. CreateProceduralPreset( pProceduralPresets, "Zero", controls, true, 0.0f );
  529. CreateProceduralPreset( pProceduralPresets, "Half", controls, true, 0.5f );
  530. CreateProceduralPreset( pProceduralPresets, "One", controls, true, 1.0f );
  531. // Add just one fake one for now
  532. CreateProceduralPreset( pProceduralPresets, "Random", controls, false );
  533. // These are the truly procedural ones...
  534. pAnimationSet->EnsureProceduralPresets();
  535. // Also load the model-specific presets
  536. g_pModelPresetGroupMgr->ApplyModelPresets( pModelName, pAnimationSet );
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Destroys existing group mappings
  540. //-----------------------------------------------------------------------------
  541. static void RemoveExistingGroupMappings( CDmeAnimationSet *pAnimationSet )
  542. {
  543. CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
  544. int nCount = groups.Count();
  545. for ( int i = 0; i < nCount; ++i )
  546. {
  547. CDmElement *pGroup = groups[i];
  548. groups.Set( i, NULL );
  549. DestroyElement( pGroup );
  550. }
  551. groups.RemoveAll();
  552. }
  553. void LoadDefaultGroupMappings( CUtlDict< CUtlString, int > &defaultGroupMapping, CUtlVector< CUtlString >& defaultGroupOrdering )
  554. {
  555. defaultGroupMapping.RemoveAll();
  556. defaultGroupOrdering.RemoveAll();
  557. KeyValues *pGroupFile = new KeyValues( "groupFile" );
  558. if ( !pGroupFile )
  559. return;
  560. if ( !pGroupFile->LoadFromFile( g_pFullFileSystem, ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE, "GAME" ) )
  561. {
  562. pGroupFile->deleteThis();
  563. return;
  564. }
  565. // Fill in defaults
  566. for ( KeyValues *sub = pGroupFile->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
  567. {
  568. const char *pGroupName = sub->GetName();
  569. if ( !pGroupName )
  570. {
  571. Warning( "%s is malformed\n", ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE );
  572. continue;
  573. }
  574. int i = defaultGroupOrdering.AddToTail();
  575. defaultGroupOrdering[i] = pGroupName;
  576. for ( KeyValues *pControl = sub->GetFirstSubKey(); pControl; pControl = pControl->GetNextKey() )
  577. {
  578. Assert( !Q_stricmp( pControl->GetName(), "control" ) );
  579. CUtlString controlName = pControl->GetString();
  580. defaultGroupMapping.Insert( controlName, pGroupName );
  581. }
  582. }
  583. pGroupFile->deleteThis();
  584. }
  585. CDmElement *FindOrAddDefaultGroupForControls( const char *pGroupName, CDmaElementArray< CDmElement > &groups, DmFileId_t fileid )
  586. {
  587. // Now see if this group exists in the array
  588. int c = groups.Count();
  589. for ( int i = 0; i < c; ++i )
  590. {
  591. CDmElement *pGroup = groups[ i ];
  592. if ( !Q_stricmp( pGroup->GetName(), pGroupName ) )
  593. return pGroup;
  594. }
  595. CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, fileid );
  596. pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
  597. groups.AddToTail( pGroup );
  598. return pGroup;
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Build group mappings
  602. //-----------------------------------------------------------------------------
  603. static void BuildGroupMappings( CDmeAnimationSet *pAnimationSet )
  604. {
  605. RemoveExistingGroupMappings( pAnimationSet );
  606. // Maps flex controls to first level "groups" by flex controller name
  607. CUtlDict< CUtlString, int > defaultGroupMapping;
  608. CUtlVector< CUtlString > defaultGroupOrdering;
  609. LoadDefaultGroupMappings( defaultGroupMapping, defaultGroupOrdering );
  610. // Create the default groups in order
  611. CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
  612. int nCount = defaultGroupOrdering.Count();
  613. for ( int i = 0; i < nCount; ++i )
  614. {
  615. const char *pGroupName = (const char *)defaultGroupOrdering[ i ];
  616. if ( !Q_stricmp( pGroupName, "IGNORE" ) )
  617. continue;
  618. CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, pAnimationSet->GetFileId() );
  619. // Fill in members
  620. pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
  621. groups.AddToTail( pGroup );
  622. }
  623. // Populate the groups with the controls
  624. CDmaElementArray<> &controls = pAnimationSet->GetControls();
  625. nCount = controls.Count();
  626. for ( int i = 0; i < nCount; ++i )
  627. {
  628. const char *pGroupName = "Unknown";
  629. const char *pControlName = controls[ i ]->GetName();
  630. // Find the default if there is one
  631. int idx = defaultGroupMapping.Find( pControlName );
  632. if ( idx != defaultGroupMapping.InvalidIndex() )
  633. {
  634. pGroupName = defaultGroupMapping[ idx ];
  635. }
  636. else if ( Q_stristr( pControlName, "root" ) || Q_stristr( pControlName, "Valve" ) )
  637. {
  638. pGroupName = "Root";
  639. }
  640. if ( !Q_stricmp( pGroupName, "IGNORE" ) )
  641. continue;
  642. CDmElement *pGroup = FindOrAddDefaultGroupForControls( pGroupName, groups, pAnimationSet->GetFileId() );
  643. // Fill in members
  644. CDmrStringArray selectedControls( pGroup, "selectedControls" );
  645. Assert( selectedControls.IsValid() );
  646. if ( selectedControls.IsValid() )
  647. {
  648. selectedControls.AddToTail( pControlName );
  649. }
  650. }
  651. }
  652. void AddIllumPositionAttribute( CDmeGameModel *pGameModel )
  653. {
  654. studiohdr_t *pHdr = pGameModel->GetStudioHdr();
  655. if ( !pHdr )
  656. return;
  657. if ( pHdr->IllumPositionAttachmentIndex() > 0 )
  658. return; // don't add attr if model already has illumposition attachment
  659. CDmAttribute *pAttr = pGameModel->AddAttributeElement< CDmeDag >( "illumPositionDag" );
  660. Assert( pAttr );
  661. if ( !pAttr )
  662. return;
  663. Assert( pGameModel->GetChildCount() > 0 );
  664. pAttr->SetValue( pGameModel->GetChild( 0 ) );
  665. }
  666. //-----------------------------------------------------------------------------
  667. // Creates an animation set
  668. //-----------------------------------------------------------------------------
  669. CDmeAnimationSet *CreateAnimationSet( CDmeFilmClip *pMovie, CDmeFilmClip *pShot,
  670. CDmeGameModel *pGameModel, const char *pAnimationSetName, int nSequenceToUse, bool bAttachToGameRecording )
  671. {
  672. CDmeAnimationSet *pAnimationSet = CreateElement< CDmeAnimationSet >( pAnimationSetName, pMovie->GetFileId() );
  673. Assert( pAnimationSet );
  674. studiohdr_t *hdr = pGameModel->GetStudioHdr();
  675. // Associate this animation set with a specific game model
  676. // FIXME: Should the game model refer back to this set?
  677. pAnimationSet->SetValue( "gameModel", pGameModel );
  678. CDmeChannelsClip* pChannelsClip = CreateChannelsClip( pAnimationSet, pShot );
  679. // Does everything associated with building facial controls on a model
  680. CFlexControlBuilder builder;
  681. builder.CreateAnimationSetControls( pMovie, pAnimationSet, pGameModel, pShot, pChannelsClip, bAttachToGameRecording );
  682. // Create animation data if there wasn't any already in the model
  683. if ( !bAttachToGameRecording )
  684. {
  685. CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "skin", pGameModel, "skin", (int)0 );
  686. CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "body", pGameModel, "body", (int)0 );
  687. CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "sequence", pGameModel, "sequence", (int)0 );
  688. CreateAnimationLogs( pChannelsClip, pGameModel, hdr, pAnimationSetName, nSequenceToUse, 0.0f, 1.0f, 0.05f );
  689. }
  690. CDmeChannelsClip *srcChannelsClip = FindChannelsClipTargetingDmeGameModel( pShot, pGameModel );
  691. CDmaElementArray<> &controls = pAnimationSet->GetControls();
  692. // First the root transform
  693. {
  694. const char *ctrlName = "rootTransform";
  695. // Add the control to the controls group
  696. CDmElement *ctrl = CreateElement< CDmElement >( ctrlName, pMovie->GetFileId() );
  697. Assert( ctrl );
  698. ctrl->SetValue< bool >( "transform", true );
  699. controls.AddToTail( ctrl );
  700. SetupRootTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, bAttachToGameRecording );
  701. }
  702. // Now add the bone transforms as well
  703. {
  704. int numbones = hdr->numbones;
  705. for ( int b = 0; b < numbones; ++b )
  706. {
  707. mstudiobone_t *bone = hdr->pBone( b );
  708. const char *name = bone->pszName();
  709. // Add the control to the controls group
  710. CDmElement *ctrl = CreateElement< CDmElement >( name, pMovie->GetFileId() );
  711. Assert( ctrl );
  712. ctrl->SetValue< bool >( "transform", true );
  713. controls.AddToTail( ctrl );
  714. SetupBoneTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, hdr, b, name, bAttachToGameRecording );
  715. }
  716. }
  717. // Now copy all remaining logs, and retime them, over to the animation set channels clip...
  718. if ( srcChannelsClip )
  719. {
  720. TransferRemainingChannels( pShot, pChannelsClip, srcChannelsClip );
  721. }
  722. // Create default preset groups for the animation set
  723. CreatePresetGroups( pAnimationSet, pGameModel->GetModelName() );
  724. // Builds the preset groups displayed in the upper left of the animation set panel
  725. BuildGroupMappings( pAnimationSet );
  726. pShot->AddAnimationSet( pAnimationSet );
  727. AddIllumPositionAttribute( pGameModel );
  728. return pAnimationSet;
  729. }