Counter Strike : Global Offensive Source Code
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.

235 lines
8.2 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // A class representing session state for the SFM
  4. //
  5. //=============================================================================
  6. #include "movieobjects/exportfacialanimation.h"
  7. #include "movieobjects/dmeclip.h"
  8. #include "movieobjects/dmeanimationset.h"
  9. #include "movieobjects/dmegamemodel.h"
  10. #include "movieobjects/dmetrackgroup.h"
  11. #include "movieobjects/dmetrack.h"
  12. #include "movieobjects/dmesound.h"
  13. #include "movieobjects/dmelog.h"
  14. #include "movieobjects/dmechannel.h"
  15. //-----------------------------------------------------------------------------
  16. // Contains export information
  17. //-----------------------------------------------------------------------------
  18. struct ExportInfo_t
  19. {
  20. CDmeFilmClip *m_pMovie;
  21. CDmeFilmClip *m_pShot;
  22. CDmeAnimationSet *m_pAnimationSet;
  23. DmeTime_t m_tExportStart;
  24. DmeTime_t m_tExportEnd;
  25. };
  26. //-----------------------------------------------------------------------------
  27. // Used to transform channel data into export time
  28. //-----------------------------------------------------------------------------
  29. static void ComputeExportChannelScaleBias( double *pScale, DmeTime_t *pBias, ExportInfo_t &info, CDmeChannel *pChannel )
  30. {
  31. DmeClipStack_t channelToGlobal;
  32. if ( pChannel->BuildClipStack( &channelToGlobal, info.m_pMovie, info.m_pShot ) )
  33. {
  34. DmeTime_t tOffset = channelToGlobal.FromChildMediaTime( DMETIME_ZERO, false );
  35. DmeTime_t tScale = channelToGlobal.FromChildMediaTime( DmeTime_t( 1.0f ), false );
  36. *pBias = tOffset - info.m_pShot->GetStartTime();
  37. *pScale = ( tScale - tOffset ).GetSeconds();
  38. }
  39. }
  40. static void GetExportTimeRange( DmeTime_t *pExportStart, DmeTime_t *pExportEnd, CDmeFilmClip *pShot )
  41. {
  42. *pExportStart = DMETIME_ZERO;
  43. *pExportEnd = pShot->GetDuration();
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Adds a log layer to the list of logs for export
  47. //-----------------------------------------------------------------------------
  48. static void AddLogLayerForExport( ExportInfo_t &info, CDmElement *pRoot, const char *pControlName, CDmeChannel *pChannel )
  49. {
  50. CDmeLog *pLog = pChannel->GetLog();
  51. if ( !pLog || pLog->GetNumLayers() == 0 )
  52. return;
  53. CDmrElementArray<> animations( pRoot, "animations" );
  54. DmeTime_t tBias;
  55. double flScale;
  56. ComputeExportChannelScaleBias( &flScale, &tBias, info, pChannel );
  57. // Only export the base layer
  58. CDmeLogLayer* pLogLayer = pLog->GetLayer( 0 )->Copy();
  59. pLogLayer->SetName( pControlName );
  60. pLogLayer->ScaleBiasKeyTimes( flScale, tBias );
  61. // Forcibly add keys @ the start + end time
  62. DmeTime_t tStartTime = ( info.m_tExportStart - tBias ) / flScale;
  63. DmeTime_t tEndTime = ( info.m_tExportEnd - tBias ) / flScale;
  64. pLogLayer->InsertKeyFromLayer( info.m_tExportStart, pLog->GetLayer(0), tStartTime );
  65. pLogLayer->InsertKeyFromLayer( info.m_tExportEnd, pLog->GetLayer(0), tEndTime );
  66. pLogLayer->RemoveKeysOutsideRange( info.m_tExportStart, info.m_tExportEnd );
  67. animations.AddToTail( pLogLayer );
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Exports animations
  71. //-----------------------------------------------------------------------------
  72. static void ExportAnimations( ExportInfo_t &info, CDmElement *pRoot )
  73. {
  74. CDmrElementArray<> animations( pRoot, "animations", true );
  75. // Build a list of all controls
  76. const CDmaElementArray< CDmElement > &controls = info.m_pAnimationSet->GetControls();
  77. int nControlCount = controls.Count();
  78. for ( int i = 0; i < nControlCount; ++i )
  79. {
  80. CDmElement *pControl = controls[i];
  81. if ( !pControl || IsTransformControl( pControl ) )
  82. continue;
  83. bool bIsStereo = IsStereoControl( pControl );
  84. if ( bIsStereo )
  85. {
  86. char pControlName[512];
  87. Q_snprintf( pControlName, sizeof(pControlName), "left_%s", pControl->GetName() );
  88. CDmeChannel *pLeftChannel = pControl->GetValueElement<CDmeChannel>( "leftvaluechannel" );
  89. AddLogLayerForExport( info, pRoot, pControlName, pLeftChannel );
  90. Q_snprintf( pControlName, sizeof(pControlName), "right_%s", pControl->GetName() );
  91. CDmeChannel *pRightChannel = pControl->GetValueElement<CDmeChannel>( "leftvaluechannel" );
  92. AddLogLayerForExport( info, pRoot, pControlName, pRightChannel );
  93. }
  94. else
  95. {
  96. CDmeChannel *pChannel = pControl->GetValueElement<CDmeChannel>( "channel" );
  97. AddLogLayerForExport( info, pRoot, pControl->GetName(), pChannel );
  98. }
  99. }
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Helper to export sounds
  103. //-----------------------------------------------------------------------------
  104. static void ExportSounds( ExportInfo_t &info, CDmElement *pRoot, CDmeClip *pClip, DmeTime_t tOffset )
  105. {
  106. CDmrElementArray<> sounds( pRoot, "sounds", true );
  107. DmeClipStack_t soundToGlobal;
  108. int gc = pClip->GetTrackGroupCount();
  109. for ( int i = 0; i < gc; ++i )
  110. {
  111. CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
  112. DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeSoundClip, pTrackGroup, pTrack, pSoundClip )
  113. const char *pGameSoundName = pSoundClip->m_Sound->m_GameSoundName;
  114. if ( !pGameSoundName || !pGameSoundName[0] )
  115. continue;
  116. if ( pSoundClip->IsMute() )
  117. continue;
  118. if ( !pSoundClip->BuildClipStack( &soundToGlobal, info.m_pMovie, pClip ) )
  119. continue;
  120. DmeTime_t tStart = soundToGlobal.FromChildMediaTime( DMETIME_ZERO, false );
  121. DmeTime_t tEnd = soundToGlobal.FromChildMediaTime( pSoundClip->GetDuration(), false );
  122. tStart -= tOffset;
  123. tEnd -= tOffset;
  124. if ( tStart >= info.m_tExportEnd || tEnd <= info.m_tExportStart )
  125. continue;
  126. const char *pName = pSoundClip->GetName();
  127. CDmElement *pSoundEvent = CreateElement<CDmElement>( pName, pRoot->GetFileId() );
  128. pSoundEvent->SetValue( "start", tStart );
  129. pSoundEvent->SetValue( "end", tEnd );
  130. pSoundEvent->SetValue( "gamesound", pGameSoundName );
  131. sounds.AddToTail( pSoundEvent );
  132. DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
  133. }
  134. }
  135. static void ExportSounds_R( ExportInfo_t &info, CDmElement *pRoot, CDmeClip *pClip, DmeTime_t tOffset )
  136. {
  137. ExportSounds( info, pRoot, pClip, tOffset );
  138. // Recurse
  139. DmeClipStack_t childToGlobal;
  140. int gc = pClip->GetTrackGroupCount();
  141. for ( int i = 0; i < gc; ++i )
  142. {
  143. CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
  144. DMETRACKGROUP_FOREACH_CLIP_START( pTrackGroup, pTrack, pChild )
  145. if ( !pChild->BuildClipStack( &childToGlobal, info.m_pMovie, pClip ) )
  146. continue;
  147. DmeTime_t tStart = childToGlobal.FromChildMediaTime( DMETIME_ZERO, false );
  148. DmeTime_t tEnd = childToGlobal.FromChildMediaTime( pChild->GetDuration(), false );
  149. tStart -= tOffset;
  150. tEnd -= tOffset;
  151. if ( tStart >= info.m_tExportEnd || tEnd <= info.m_tExportStart )
  152. continue;
  153. ExportSounds_R( info, pRoot, pChild, tOffset );
  154. DMETRACKGROUP_FOREACH_CLIP_END()
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Exports sounds, default implementation
  159. //-----------------------------------------------------------------------------
  160. static void ExportSounds( ExportInfo_t &info, CDmElement *pRoot )
  161. {
  162. DmeTime_t tOffset = info.m_pShot->GetStartTime();
  163. ExportSounds( info, pRoot, info.m_pMovie, tOffset );
  164. ExportSounds_R( info, pRoot, info.m_pShot, tOffset );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Exports an .fac file
  168. //-----------------------------------------------------------------------------
  169. bool ExportFacialAnimation( const char *pFileName, CDmeFilmClip *pMovie, CDmeFilmClip *pShot, CDmeAnimationSet *pAnimationSet )
  170. {
  171. if ( !pMovie || !pShot || !pAnimationSet )
  172. return false;
  173. const char *pFileFormat = "facial_animation";
  174. CDmElement *pRoot = CreateElement< CDmElement >( pAnimationSet->GetName(), DMFILEID_INVALID );
  175. ExportInfo_t info;
  176. info.m_pMovie = pMovie;
  177. info.m_pShot = pShot;
  178. info.m_pAnimationSet = pAnimationSet;
  179. GetExportTimeRange( &info.m_tExportStart, &info.m_tExportEnd, pShot );
  180. CDmeGameModel *pGameModel = pAnimationSet->GetValueElement<CDmeGameModel>( "gameModel" );
  181. if ( pGameModel )
  182. {
  183. pRoot->SetValue( "gamemodel", pGameModel->GetModelName() );
  184. }
  185. ExportAnimations( info, pRoot );
  186. ExportSounds( info, pRoot );
  187. pRoot->SetFileId( DMFILEID_INVALID, TD_DEEP );
  188. const char *pEncoding = "keyvalues2_flat";
  189. bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pEncoding, pFileFormat, pRoot );
  190. DestroyElement( pRoot, TD_DEEP );
  191. return bOk;
  192. }