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.

950 lines
36 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // A class used to build flex animation controls for an animation set
  4. //
  5. //=============================================================================
  6. #include "sfmobjects/flexcontrolbuilder.h"
  7. #include "studio.h"
  8. #include "movieobjects/dmeanimationset.h"
  9. #include "movieobjects/dmeclip.h"
  10. #include "movieobjects/dmetrackgroup.h"
  11. #include "movieobjects/dmetrack.h"
  12. #include "movieobjects/dmegamemodel.h"
  13. #include "movieobjects/dmechannel.h"
  14. #include "movieobjects/dmebalancetostereocalculatoroperator.h"
  15. #include "tier1/utlsymbol.h"
  16. // Names of attributes in controls we attach channels to
  17. #define CONTROL_CHANNEL_ATTRIBUTE_COUNT 4
  18. static const char *s_pChannelControls[CONTROL_CHANNEL_ATTRIBUTE_COUNT] =
  19. {
  20. "channel", "valuechannel", "balancechannel", "multilevelchannel"
  21. };
  22. //-----------------------------------------------------------------------------
  23. // Flex controller
  24. //-----------------------------------------------------------------------------
  25. class CDefaultGlobalFlexController : public IGlobalFlexController
  26. {
  27. public:
  28. CDefaultGlobalFlexController() : m_SymbolTable( 0, 32, true ) {}
  29. virtual int FindGlobalFlexController( const char *name )
  30. {
  31. return m_SymbolTable.AddString( name );
  32. }
  33. virtual const char *GetGlobalFlexControllerName( int idx )
  34. {
  35. return m_SymbolTable.String( (CUtlSymbol)idx );
  36. }
  37. private:
  38. CUtlSymbolTable m_SymbolTable;
  39. };
  40. static CDefaultGlobalFlexController s_GlobalFlexController;
  41. extern IGlobalFlexController *g_pGlobalFlexController;
  42. //-----------------------------------------------------------------------------
  43. // This builds a list of the desired flex controllers we need to have controls for
  44. // by the time we're all done with this enormous process.
  45. //-----------------------------------------------------------------------------
  46. void CFlexControlBuilder::BuildDesiredFlexControlList( CDmeGameModel *pGameModel )
  47. {
  48. CStudioHdr cHdr( pGameModel->GetStudioHdr() );
  49. LocalFlexController_t nCount = cHdr.numflexcontrollers();
  50. m_FlexControllerInfo.EnsureCapacity( nCount );
  51. for ( LocalFlexController_t i = LocalFlexController_t(0); i < nCount; ++i )
  52. {
  53. int j = m_FlexControllerInfo.AddToTail();
  54. FlexControllerInfo_t& info = m_FlexControllerInfo[j];
  55. mstudioflexcontroller_t *pFlex = cHdr.pFlexcontroller( i );
  56. Q_strncpy( info.m_pFlexControlName, pFlex->pszName(), sizeof( info.m_pFlexControlName ) );
  57. info.m_nGlobalIndex = g_pGlobalFlexController->FindGlobalFlexController( pFlex->pszName() );
  58. info.m_flDefaultValue = 0.0f;
  59. if ( pFlex->max != pFlex->min )
  60. {
  61. // FIXME: Is this the correct default value?
  62. info.m_flDefaultValue = ( 0.0f - pFlex->min ) / ( pFlex->max - pFlex->min );
  63. }
  64. }
  65. }
  66. //-----------------------------------------------------------------------------
  67. // This builds a list of the desired input controls we need to have controls for
  68. // by the time we're all done with this enormous process.
  69. //-----------------------------------------------------------------------------
  70. void CFlexControlBuilder::BuildDesiredControlList( CDmeGameModel *pGameModel )
  71. {
  72. int nCount = m_FlexControllerInfo.Count();
  73. for ( int i = 0; i < nCount; ++i )
  74. {
  75. int j = m_ControlInfo.AddToTail();
  76. ControlInfo_t &controlInfo = m_ControlInfo[j];
  77. memset( &controlInfo, 0, sizeof(ControlInfo_t) );
  78. FlexControllerInfo_t& info = m_FlexControllerInfo[i];
  79. const char *pFlexName = info.m_pFlexControlName;
  80. // Deal with stereo/mono controls
  81. if ( !Q_strnicmp( "right_", pFlexName, 6 ) && ( i < nCount - 1 ) )
  82. {
  83. FlexControllerInfo_t& leftInfo = m_FlexControllerInfo[i+1];
  84. Assert( !Q_strnicmp( "left_", leftInfo.m_pFlexControlName, 5 ) );
  85. controlInfo.m_bIsStereo = true;
  86. controlInfo.m_pControllerIndex[ OUTPUT_RIGHT ] = i;
  87. controlInfo.m_pControllerIndex[ OUTPUT_LEFT ] = i+1;
  88. Q_strncpy( controlInfo.m_pControlName, pFlexName + 6, sizeof(controlInfo.m_pControlName) );
  89. // Convert default values into value/balance
  90. LeftRightToValueBalance( &controlInfo.m_pDefaultValue[ CONTROL_VALUE ],
  91. &controlInfo.m_pDefaultValue[ CONTROL_BALANCE ],
  92. leftInfo.m_flDefaultValue, info.m_flDefaultValue );
  93. // Skip the 'left_' flex control
  94. ++i;
  95. }
  96. else
  97. {
  98. controlInfo.m_bIsStereo = false;
  99. controlInfo.m_pControllerIndex[ OUTPUT_MONO ] = i;
  100. controlInfo.m_pControllerIndex[ OUTPUT_LEFT ] = -1;
  101. Q_strncpy( controlInfo.m_pControlName, pFlexName, sizeof(controlInfo.m_pControlName) );
  102. controlInfo.m_pDefaultValue[ CONTROL_VALUE ] = info.m_flDefaultValue;
  103. controlInfo.m_pDefaultValue[ CONTROL_BALANCE ] = 0.5f;
  104. }
  105. // Deal with multi controls
  106. controlInfo.m_bIsMulti = ( i+1 < nCount ) && !Q_strnicmp( "multi_", m_FlexControllerInfo[ i+1 ].m_pFlexControlName, 6 );
  107. if ( controlInfo.m_bIsMulti )
  108. {
  109. FlexControllerInfo_t& multiInfo = m_FlexControllerInfo[i+1];
  110. controlInfo.m_pControllerIndex[ OUTPUT_MULTILEVEL ] = i+1;
  111. controlInfo.m_pDefaultValue[ CONTROL_MULTILEVEL ] = multiInfo.m_flDefaultValue;
  112. // Skip the 'multi_' flex control
  113. ++i;
  114. }
  115. else
  116. {
  117. controlInfo.m_pControllerIndex[ OUTPUT_MULTILEVEL ] = -1;
  118. controlInfo.m_pDefaultValue[ CONTROL_MULTILEVEL ] = 0.5f;
  119. }
  120. }
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Finds a desired flex controller index in the m_FlexControllerInfo array
  124. //-----------------------------------------------------------------------------
  125. int CFlexControlBuilder::FindDesiredFlexController( const char *pFlexControllerName ) const
  126. {
  127. int nCount = m_FlexControllerInfo.Count();
  128. for ( int i = 0; i < nCount; ++i )
  129. {
  130. if ( !Q_stricmp( pFlexControllerName, m_FlexControllerInfo[i].m_pFlexControlName ) )
  131. return i;
  132. }
  133. return -1;
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Removes a channel from the channels clip referring to it.
  137. //-----------------------------------------------------------------------------
  138. void CFlexControlBuilder::RemoveChannelFromClips( CDmeChannel *pChannel )
  139. {
  140. // First, try to grab the channels referring to this op
  141. CUtlVector< CDmeChannelsClip* > channelsClips;
  142. FindAncestorsReferencingElement( pChannel, channelsClips );
  143. int nChannelsClips = channelsClips.Count();
  144. for ( int i = 0; i < nChannelsClips; ++i )
  145. {
  146. channelsClips[ i ]->RemoveChannel( pChannel );
  147. }
  148. // Next, remove the channel from values controls it may be attached to
  149. for ( int i = 0; i < CONTROL_CHANNEL_ATTRIBUTE_COUNT; ++i )
  150. {
  151. UtlSymId_t symChannelControl = g_pDataModel->GetSymbol( s_pChannelControls[i] );
  152. CDmElement *pControl = FindReferringElement< CDmElement >( pChannel, symChannelControl );
  153. if ( pControl )
  154. {
  155. pControl->RemoveAttribute( s_pChannelControls[i] );
  156. }
  157. }
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Removes a stereo operator from the animation set referring to it
  161. //-----------------------------------------------------------------------------
  162. void CFlexControlBuilder::RemoveStereoOpFromSet( CDmeBalanceToStereoCalculatorOperator *pSteroOp )
  163. {
  164. // First, try to grab the channel referring to this op
  165. const static UtlSymId_t symOperators = g_pDataModel->GetSymbol( "operators" );
  166. CDmeAnimationSet *pAnimationSet = FindReferringElement< CDmeAnimationSet >( pSteroOp, symOperators );
  167. if ( pAnimationSet )
  168. {
  169. pAnimationSet->RemoveOperator( pSteroOp );
  170. }
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Blows away the various elements trying to control a flex controller op
  174. //-----------------------------------------------------------------------------
  175. void CFlexControlBuilder::CleanupExistingFlexController( CDmeGameModel *pGameModel, CDmeGlobalFlexControllerOperator *pOp )
  176. {
  177. CDmeBalanceToStereoCalculatorOperator *pStereoOp;
  178. // First, try to grab the channel referring to this op
  179. const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
  180. CDmeChannel *pChannel = FindReferringElement< CDmeChannel >( pOp, symToElement );
  181. if ( !pChannel )
  182. goto destroyOp;
  183. // Sometimes a stereo op will be read from by this channel
  184. pStereoOp = CastElement< CDmeBalanceToStereoCalculatorOperator >( pChannel->GetFromElement() );
  185. RemoveChannelFromClips( pChannel );
  186. DestroyElement( pChannel );
  187. if ( !pStereoOp )
  188. goto destroyOp;
  189. RemoveStereoOpFromSet( pStereoOp );
  190. // If we have a stereo op, then blow away all channels targetting that stereo op
  191. DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pStereoOp->GetHandle() );
  192. DmAttributeReferenceIterator_t next;
  193. for ( ; i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; i = next )
  194. {
  195. next = g_pDataModel->NextAttributeReferencingElement( i );
  196. CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
  197. pChannel = CastElement<CDmeChannel>( pAttribute->GetOwner() );
  198. if ( pChannel && pAttribute->GetNameSymbol() == symToElement )
  199. {
  200. RemoveChannelFromClips( pChannel );
  201. DestroyElement( pChannel );
  202. }
  203. }
  204. DestroyElement( pStereoOp );
  205. destroyOp:
  206. pGameModel->RemoveGlobalFlexController( pOp );
  207. DestroyElement( pOp );
  208. }
  209. bool RemoveChannelIfUnused( CDmeChannel *pChannel, CDmeChannelsClip *pChannelsClip )
  210. {
  211. if ( !pChannel )
  212. return false;
  213. if ( pChannel->GetToElement() != NULL )
  214. return false;
  215. pChannelsClip->RemoveChannel( pChannel );
  216. DestroyElement( pChannel );
  217. return true;
  218. }
  219. // finds controls whose channels don't point to anything anymore, and deletes both the channels and the control
  220. void CFlexControlBuilder::RemoveUnusedControlsAndChannels( CDmeAnimationSet *pAnimationSet, CDmeChannelsClip *pChannelsClip )
  221. {
  222. CDmrElementArray<> controls = pAnimationSet->GetControls();
  223. int nControls = controls.Count();
  224. for ( int i = nControls - 1; i >= 0 ; --i )
  225. {
  226. CDmElement *pControl = controls[ i ];
  227. if ( pControl )
  228. {
  229. bool bRemoved = RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "channel" ), pChannelsClip );
  230. bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "valuechannel" ), pChannelsClip );
  231. bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "balancechannel" ), pChannelsClip );
  232. bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "multilevelchannel" ), pChannelsClip );
  233. if ( !bRemoved )
  234. continue;
  235. DestroyElement( pControl );
  236. }
  237. controls.Remove( i );
  238. }
  239. }
  240. //-----------------------------------------------------------------------------
  241. // This removes existing controls on the animationset that aren't in the desired state
  242. //-----------------------------------------------------------------------------
  243. void CFlexControlBuilder::RemoveUnusedExistingFlexControllers( CDmeGameModel *pGameModel )
  244. {
  245. // These are the current flex controllers
  246. // NOTE: Name of these controllers should match the names of the flex controllers
  247. int nCount = pGameModel->NumGlobalFlexControllers();
  248. for ( int i = nCount; --i >= 0; )
  249. {
  250. CDmeGlobalFlexControllerOperator *pOp = pGameModel->GetGlobalFlexController( i );
  251. Assert( pOp );
  252. if ( pOp && FindDesiredFlexController( pOp->GetName() ) < 0 )
  253. {
  254. Msg( "removing flex controller %s\n", pOp->GetName() );
  255. CleanupExistingFlexController( pGameModel, pOp );
  256. }
  257. }
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Returns an existing mono log
  261. //-----------------------------------------------------------------------------
  262. void CFlexControlBuilder::GetExistingMonoLog( ExistingLogInfo_t *pExistingLog,
  263. CDmeFilmClip *pClip, CDmeGlobalFlexControllerOperator *pMonoOp )
  264. {
  265. pExistingLog->m_pLog = NULL;
  266. const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
  267. CDmeChannel *pMonoChannel = FindReferringElement< CDmeChannel >( pMonoOp, symToElement );
  268. if ( !pMonoChannel )
  269. return;
  270. // First, try to grab the channel referring to this op
  271. CDmeFloatLog *pLog = CastElement< CDmeFloatLog >( pMonoChannel->GetLog() );
  272. if ( !pLog )
  273. return;
  274. if ( ComputeChannelTimeTransform( &pExistingLog->m_GlobalOffset, &pExistingLog->m_flGlobalScale, pClip, pMonoChannel ) )
  275. {
  276. pExistingLog->m_pLog = pLog;
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Finds a channels clip containing a particular channel
  281. //-----------------------------------------------------------------------------
  282. CDmeChannelsClip* CFlexControlBuilder::FindChannelsClipContainingChannel( CDmeFilmClip *pClip, CDmeChannel *pSearch )
  283. {
  284. int gc = pClip->GetTrackGroupCount();
  285. for ( int i = 0; i < gc; ++i )
  286. {
  287. CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
  288. DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
  289. int nChannels = pChannelsClip->m_Channels.Count();
  290. for ( int j = 0; j < nChannels; ++j )
  291. {
  292. CDmeChannel *pChannel = pChannelsClip->m_Channels[ j ];
  293. if ( pChannel == pSearch )
  294. return pChannelsClip;
  295. }
  296. DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
  297. }
  298. return NULL;
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Computes a global offset and scale to convert from log time to global time
  302. //-----------------------------------------------------------------------------
  303. void CFlexControlBuilder::ComputeChannelTimeTransform( DmeTime_t *pOffset, double *pScale, CDmeChannelsClip *pChannelsClip )
  304. {
  305. // Determine the global time of the start + end of the log
  306. DmeClipStack_t srcStack;
  307. pChannelsClip->BuildClipStack( &srcStack, m_pMovie, NULL );
  308. *pOffset = CDmeClip::FromChildMediaTime( srcStack, DMETIME_ZERO, false );
  309. DmeTime_t duration = CDmeClip::FromChildMediaTime( srcStack, DmeTime_t( 10000 ), false );
  310. duration -= *pOffset;
  311. *pScale = duration.GetSeconds();
  312. }
  313. bool CFlexControlBuilder::ComputeChannelTimeTransform( DmeTime_t *pOffset, double *pScale, CDmeFilmClip* pClip, CDmeChannel* pChannel )
  314. {
  315. CDmeChannelsClip *pChannelsClip = FindChannelsClipContainingChannel( pClip, pChannel );
  316. if ( !pChannelsClip )
  317. return false;
  318. ComputeChannelTimeTransform( pOffset, pScale, pChannelsClip );
  319. return true;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Returns an existing value/balance log
  323. //-----------------------------------------------------------------------------
  324. void CFlexControlBuilder::GetExistingVBLog( ExistingLogInfo_t *pLogs, CDmeFilmClip *pClip, CDmeBalanceToStereoCalculatorOperator *pStereoOp )
  325. {
  326. // Stereo operators always have value/balance logs attached
  327. DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pStereoOp->GetHandle() );
  328. for ( ; i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; i = g_pDataModel->NextAttributeReferencingElement( i ) )
  329. {
  330. CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
  331. CDmeChannel *pChannel = CastElement< CDmeChannel >( pAttribute->GetOwner() );
  332. const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
  333. if ( !pChannel || pAttribute->GetNameSymbol() != symToElement )
  334. continue;
  335. const char *pToAttributeName = pChannel->GetToAttribute()->GetName();
  336. int nLogIndex = -1;
  337. if ( !Q_stricmp( pToAttributeName, "value" ) )
  338. {
  339. nLogIndex = CONTROL_VALUE;
  340. }
  341. else if ( !Q_stricmp( pToAttributeName, "balance" ) )
  342. {
  343. nLogIndex = CONTROL_BALANCE;
  344. }
  345. else
  346. {
  347. continue;
  348. }
  349. CDmeFloatLog *pLog = CastElement< CDmeFloatLog >( pChannel->GetLog() );
  350. if ( !pLog )
  351. continue;
  352. // Compute a scale and offset transforming log time into global time
  353. if ( !ComputeChannelTimeTransform( &pLogs[nLogIndex].m_GlobalOffset, &pLogs[nLogIndex].m_flGlobalScale, pClip, pChannel ) )
  354. continue;
  355. // Detach the
  356. pLogs[nLogIndex].m_pLog = pLog;
  357. pChannel->SetLog( NULL ); // Detach
  358. }
  359. }
  360. static void AddKeyToLogs( CDmeTypedLog< float > *valueLog, CDmeTypedLog< float > *balanceLog, const DmeTime_t& keyTime, float lval, float rval )
  361. {
  362. // Convert left right into value, balance
  363. float value, balance;
  364. LeftRightToValueBalance( &value, &balance, lval, rval );
  365. // Msg( "%.5f setting l/r %f %f to value %f balance %f\n",
  366. // keyTime.GetSeconds(), lval, rval, value, balance );
  367. valueLog->SetKey( keyTime, value );
  368. balanceLog->SetKey( keyTime, balance );
  369. }
  370. static void ConvertLRToVBLog( CDmeFloatLog *pValueLog, CDmeFloatLog *pBalanceLog, CDmeFloatLog *pLeftLog, CDmeFloatLog *pRightLog, DmeTime_t rightOffset, double flRightScale )
  371. {
  372. int lc = pLeftLog->GetKeyCount();
  373. int rc = pRightLog->GetKeyCount();
  374. int nLeft = 0, nRight = 0;
  375. while ( nLeft < lc || nRight < rc )
  376. {
  377. bool bUseLeft = ( nLeft < lc );
  378. bool bUseRight = ( nRight < rc );
  379. DmeTime_t leftKeyTime = bUseLeft ? pLeftLog->GetKeyTime( nLeft ) : DMETIME_MAXTIME;
  380. DmeTime_t rightKeyTime = bUseRight ? pRightLog->GetKeyTime( nRight ) : DMETIME_MAXTIME;
  381. // Transform rightKeyTime into leftKeyTime space
  382. if ( bUseRight )
  383. {
  384. rightKeyTime.SetSeconds( rightKeyTime.GetSeconds() * flRightScale );
  385. rightKeyTime += rightOffset;
  386. }
  387. if ( leftKeyTime == rightKeyTime )
  388. {
  389. float lval = pLeftLog->GetKeyValue( nLeft++ );
  390. float rval = pRightLog->GetKeyValue( nRight++ );
  391. AddKeyToLogs( pValueLog, pBalanceLog, leftKeyTime, lval, rval );
  392. continue;
  393. }
  394. if ( leftKeyTime < rightKeyTime )
  395. {
  396. // pull a value from the right log at the leftKeyTime
  397. // and advance to the next sample on the left side
  398. float lval = pLeftLog->GetKeyValue( nLeft++ );
  399. float rval = pRightLog->GetValue( leftKeyTime );
  400. AddKeyToLogs( pValueLog, pBalanceLog, leftKeyTime, lval, rval );
  401. continue;
  402. }
  403. // Pull a value from the left log at the rightKeyTime
  404. // and advance to the next sample on the right side
  405. float lval = pLeftLog->GetValue( rightKeyTime );
  406. float rval = pRightLog->GetKeyValue( nRight++ );
  407. AddKeyToLogs( pValueLog, pBalanceLog, rightKeyTime, lval, rval );
  408. }
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Converts an existing value/balance log
  412. //-----------------------------------------------------------------------------
  413. void CFlexControlBuilder::ConvertExistingLRLogs( ExistingLogInfo_t *pLogs,
  414. CDmeFilmClip *pClip, CDmeChannel *pLeftChannel, CDmeChannel *pRightChannel )
  415. {
  416. CDmeFloatLog *pRightLog = CastElement< CDmeFloatLog >( pRightChannel->GetLog() );
  417. CDmeFloatLog *pLeftLog = CastElement< CDmeFloatLog >( pLeftChannel->GetLog() );
  418. if ( !pRightLog || !pLeftLog )
  419. return;
  420. // Compute a scale + offset to transform the right log to get it in the same space as the left log
  421. DmeTime_t leftOffset, rightOffset;
  422. double flLeftScale, flRightScale;
  423. if ( !ComputeChannelTimeTransform( &leftOffset, &flLeftScale, pClip, pLeftChannel ) )
  424. return;
  425. if ( !ComputeChannelTimeTransform( &rightOffset, &flRightScale, pClip, pRightChannel ) )
  426. return;
  427. flRightScale = ( flRightScale != 0.0f ) ? flLeftScale / flRightScale : 1.0;
  428. rightOffset = leftOffset - DmeTime_t( rightOffset.GetSeconds() * flRightScale );
  429. pLogs[CONTROL_VALUE].m_pLog = CreateElement< CDmeFloatLog >( "value" );
  430. pLogs[CONTROL_VALUE].m_GlobalOffset = leftOffset;
  431. pLogs[CONTROL_VALUE].m_flGlobalScale = flLeftScale;
  432. pLogs[CONTROL_BALANCE].m_pLog = CreateElement< CDmeFloatLog >( "balance" );
  433. pLogs[CONTROL_BALANCE].m_GlobalOffset = leftOffset; // NOTE: This is correct! All logs are transformed into left channel time
  434. pLogs[CONTROL_BALANCE].m_flGlobalScale = flLeftScale;
  435. ConvertLRToVBLog( pLogs[CONTROL_VALUE].m_pLog, pLogs[CONTROL_BALANCE].m_pLog,
  436. pLeftLog, pRightLog, rightOffset, flRightScale );
  437. // DestroyElement( pLeftLog );
  438. // DestroyElement( pRightLog );
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Returns an existing stereo log, performing conversion if necessary
  442. //-----------------------------------------------------------------------------
  443. void CFlexControlBuilder::GetExistingStereoLog( ExistingLogInfo_t *pLogs, CDmeFilmClip *pClip,
  444. CDmeGlobalFlexControllerOperator *pRightOp, CDmeGlobalFlexControllerOperator *pLeftOp )
  445. {
  446. pLogs[CONTROL_VALUE].m_pLog = NULL;
  447. pLogs[CONTROL_BALANCE].m_pLog = NULL;
  448. // First, try to grab the channel referring to this op
  449. const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
  450. CDmeChannel *pChannel = FindReferringElement< CDmeChannel >( pRightOp, symToElement );
  451. if ( !pChannel )
  452. return;
  453. // Sometimes a stereo op will be read from by this channel
  454. CDmeBalanceToStereoCalculatorOperator *pStereoOp = CastElement< CDmeBalanceToStereoCalculatorOperator >( pChannel->GetFromElement() );
  455. if ( pStereoOp )
  456. {
  457. GetExistingVBLog( pLogs, pClip, pStereoOp );
  458. return;
  459. }
  460. // In this case, we recorded game data and we have left/right logs
  461. CDmeChannel *pLeftChannel = FindReferringElement< CDmeChannel >( pLeftOp, symToElement );
  462. if ( !pLeftChannel )
  463. return;
  464. ConvertExistingLRLogs( pLogs, pClip, pLeftChannel, pChannel );
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Fixup list of existing flex controller logs
  468. // - reattach flex controls that were removed from the gamemodel's list
  469. //-----------------------------------------------------------------------------
  470. void CFlexControlBuilder::FixupExistingFlexControlLogList( CDmeFilmClip *pCurrentClip, CDmeGameModel *pGameModel )
  471. {
  472. int nTrackGroups = pCurrentClip->GetTrackGroupCount();
  473. for ( int gi = 0; gi < nTrackGroups; ++gi )
  474. {
  475. CDmeTrackGroup *pTrackGroup = pCurrentClip->GetTrackGroup( gi );
  476. if ( !pTrackGroup )
  477. continue;
  478. DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
  479. int nChannels = pChannelsClip->m_Channels.Count();
  480. for ( int ci = 0; ci < nChannels; ++ci )
  481. {
  482. CDmeChannel *pChannel = pChannelsClip->m_Channels[ ci ];
  483. if ( !pChannel )
  484. continue;
  485. CDmeGlobalFlexControllerOperator *pOp = CastElement< CDmeGlobalFlexControllerOperator >( pChannel->GetToElement() );
  486. if ( !pOp )
  487. continue;
  488. if ( pOp->m_gameModel != pGameModel->GetHandle() )
  489. continue;
  490. int nGlobalIndex = pOp->GetGlobalIndex();
  491. CDmeGlobalFlexControllerOperator *pFoundOp = pGameModel->FindGlobalFlexController( nGlobalIndex );
  492. if ( pFoundOp == pOp )
  493. continue;
  494. if ( !pFoundOp )
  495. {
  496. Msg( "adding missing flex controller %d %s\n", nGlobalIndex, pOp->GetName() );
  497. pFoundOp = pGameModel->AddGlobalFlexController( pOp->GetName(), nGlobalIndex );
  498. }
  499. pChannel->SetOutput( pFoundOp, pChannel->GetToAttribute()->GetName() );
  500. if ( pChannel->GetFromElement() == pOp )
  501. {
  502. pChannel->SetInput( pFoundOp, pChannel->GetFromAttribute()->GetName() );
  503. }
  504. Msg( "removing duplicate flex controller %d %s\n", nGlobalIndex, pOp->GetName() );
  505. RemoveElementFromRefereringAttributes( pOp );
  506. DestroyElement( pOp );
  507. }
  508. DMETRACKGROUP_FOREACH_CLIP_TYPE_END();
  509. }
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Build list of existing flex controller logs
  513. //-----------------------------------------------------------------------------
  514. void CFlexControlBuilder::BuildExistingFlexControlLogList( CDmeFilmClip *pCurrentClip, CDmeGameModel *pGameModel )
  515. {
  516. // These are the current flex controllers that also exist in the desired list
  517. // NOTE: Name of these controllers should match the names of the flex controllers
  518. int nCount = m_ControlInfo.Count();
  519. for ( int i = 0; i < nCount; ++i )
  520. {
  521. ControlInfo_t &info = m_ControlInfo[i];
  522. if ( info.m_bIsStereo )
  523. {
  524. int nRightFlex = info.m_pControllerIndex[ OUTPUT_RIGHT ];
  525. int nLeftFlex = info.m_pControllerIndex[ OUTPUT_LEFT ];
  526. FlexControllerInfo_t *pRightInfo = &m_FlexControllerInfo[nRightFlex];
  527. FlexControllerInfo_t *pLeftInfo = &m_FlexControllerInfo[nLeftFlex];
  528. CDmeGlobalFlexControllerOperator *pRightOp = pGameModel->FindGlobalFlexController( pRightInfo->m_nGlobalIndex );
  529. CDmeGlobalFlexControllerOperator *pLeftOp = pGameModel->FindGlobalFlexController( pLeftInfo->m_nGlobalIndex );
  530. if ( pRightOp && pLeftOp )
  531. {
  532. Msg( "replacing stereo flex controllers %s and %s\n", pRightOp->GetName(), pRightOp->GetName() );
  533. GetExistingStereoLog( info.m_pExistingLog, pCurrentClip, pRightOp, pLeftOp );
  534. CleanupExistingFlexController( pGameModel, pRightOp );
  535. CleanupExistingFlexController( pGameModel, pLeftOp );
  536. }
  537. }
  538. else
  539. {
  540. int nFlex = info.m_pControllerIndex[ OUTPUT_MONO ];
  541. FlexControllerInfo_t *pInfo = &m_FlexControllerInfo[nFlex];
  542. CDmeGlobalFlexControllerOperator *pMonoOp = pGameModel->FindGlobalFlexController( pInfo->m_nGlobalIndex );
  543. if ( pMonoOp )
  544. {
  545. Msg( "replacing mono flex controller %s\n", pMonoOp->GetName() );
  546. GetExistingMonoLog( &info.m_pExistingLog[CONTROL_VALUE], pCurrentClip, pMonoOp );
  547. CleanupExistingFlexController( pGameModel, pMonoOp );
  548. }
  549. }
  550. if ( info.m_bIsMulti )
  551. {
  552. int nFlex = info.m_pControllerIndex[ OUTPUT_MULTILEVEL ];
  553. FlexControllerInfo_t *pMultiInfo = &m_FlexControllerInfo[ nFlex ];
  554. CDmeGlobalFlexControllerOperator *pMultiOp = pGameModel->FindGlobalFlexController( pMultiInfo->m_nGlobalIndex );
  555. if ( pMultiOp )
  556. {
  557. Msg( "replacing multi flex controller %s\n", pMultiOp->GetName() );
  558. GetExistingMonoLog( &info.m_pExistingLog[CONTROL_MULTILEVEL], pCurrentClip, pMultiOp );
  559. CleanupExistingFlexController( pGameModel, pMultiOp );
  560. }
  561. }
  562. }
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Creates a flex controller and a channel connecting it to a control
  566. //-----------------------------------------------------------------------------
  567. struct FlexOpInfo_t
  568. {
  569. const char *m_pControlAttributeName;
  570. const char *m_pControlLinkAttributeName;
  571. };
  572. static FlexOpInfo_t s_pFlexOpInfo[2] =
  573. {
  574. { "value", "" },
  575. { "multilevel", "multilevel" },
  576. };
  577. void CFlexControlBuilder::BuildFlexControllerOps( CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip, ControlInfo_t &info, ControlField_t field )
  578. {
  579. const FlexOpInfo_t& flexInfo = s_pFlexOpInfo[ ( field == CONTROL_VALUE ) ? 0 : 1 ];
  580. // Get the global flex controller name and index
  581. const FlexControllerInfo_t& fcInfo = m_FlexControllerInfo[ info.m_pControllerIndex[field] ];
  582. // Create operator which drives facial flex setting
  583. CDmeGlobalFlexControllerOperator *pFlexControllerOp = pGameModel->AddGlobalFlexController(
  584. fcInfo.m_pFlexControlName, fcInfo.m_nGlobalIndex );
  585. // Create a channel which passes from the control value to the global flex controller
  586. char pName[ 256 ];
  587. Q_snprintf( pName, sizeof( pName ), "%s_flex_channel", fcInfo.m_pFlexControlName );
  588. info.m_ppControlChannel[field] = pChannelsClip->CreatePassThruConnection( pName,
  589. info.m_pControl, flexInfo.m_pControlAttributeName, pFlexControllerOp, "flexWeight" );
  590. // NOTE: The animation set slider panel looks for these custom attributes
  591. Q_snprintf( pName, sizeof(pName), "%schannel", flexInfo.m_pControlLinkAttributeName );
  592. info.m_pControl->SetValue( pName, info.m_ppControlChannel[field] );
  593. // Switch the channel into play mode by default
  594. info.m_ppControlChannel[field]->SetMode( CM_PLAY );
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Creates a flex controller and a channel connecting it to stereo controls
  598. //-----------------------------------------------------------------------------
  599. static const char *s_pStereoOutputPrefix[2] =
  600. {
  601. "right",
  602. "left",
  603. };
  604. static const char *s_pStereoInputPrefix[2] =
  605. {
  606. "value",
  607. "balance",
  608. };
  609. void CFlexControlBuilder::BuildStereoFlexControllerOps( CDmeAnimationSet *pAnimationSet,
  610. CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip, ControlInfo_t &info )
  611. {
  612. // Create an operator which converts value/balance to left/right
  613. CDmrElementArray< CDmeOperator > operators = pAnimationSet->GetOperators();
  614. CDmeBalanceToStereoCalculatorOperator *pStereoCalcOp =
  615. CreateElement< CDmeBalanceToStereoCalculatorOperator >( info.m_pControlName, pAnimationSet->GetFileId() );
  616. operators.AddToTail( pStereoCalcOp->GetHandle() );
  617. pStereoCalcOp->SetValue< float >( "value", info.m_pDefaultValue[CONTROL_VALUE] );
  618. pStereoCalcOp->SetValue< float >( "balance", info.m_pDefaultValue[CONTROL_BALANCE] );
  619. // Connect channels from animation set controls to balance operator to flex controller operators
  620. char pChannelName[ 256 ];
  621. char pResultName[ 256 ];
  622. for ( int i = 0; i < 2; ++i )
  623. {
  624. // Get the global flex controller name and index
  625. const FlexControllerInfo_t& fcInfo = m_FlexControllerInfo[ info.m_pControllerIndex[i] ];
  626. // Create an operator which drives facial flex setting
  627. CDmeGlobalFlexControllerOperator *pFlexControllerOp = pGameModel->AddGlobalFlexController(
  628. fcInfo.m_pFlexControlName, fcInfo.m_nGlobalIndex );
  629. // Now create a channel which connects the output of the stereo op to the flex controller op
  630. Q_snprintf( pResultName, sizeof( pResultName ), "result_%s", s_pStereoOutputPrefix[ i ] );
  631. Q_snprintf( pChannelName, sizeof( pChannelName ), "%s_flex_channel", fcInfo.m_pFlexControlName );
  632. pChannelsClip->CreatePassThruConnection( pChannelName, pStereoCalcOp,
  633. pResultName, pFlexControllerOp, "flexWeight" );
  634. // Create a channel which connects the control to the input of the stereo op
  635. Q_snprintf( pChannelName, sizeof( pChannelName ), "%s_%s_channel", info.m_pControlName, s_pStereoInputPrefix[ i ] );
  636. info.m_ppControlChannel[i] = pChannelsClip->CreatePassThruConnection( pChannelName,
  637. info.m_pControl, s_pStereoInputPrefix[ i ], pStereoCalcOp, s_pStereoInputPrefix[ i ] );
  638. // NOTE: The animation set slider panel looks for these custom attributes
  639. Q_snprintf( pChannelName, sizeof(pChannelName), "%schannel", s_pStereoInputPrefix[ i ] );
  640. info.m_pControl->SetValue( pChannelName, info.m_ppControlChannel[i] );
  641. // Switch the channel into play mode by default
  642. info.m_ppControlChannel[i]->SetMode( CM_PLAY );
  643. }
  644. }
  645. //-----------------------------------------------------------------------------
  646. // Build the infrastructure of the ops that connect that control to the dmegamemodel
  647. //-----------------------------------------------------------------------------
  648. void CFlexControlBuilder::AttachControlsToGameModel( CDmeAnimationSet *pAnimationSet,
  649. CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip )
  650. {
  651. // Build the infrastructure of the ops that connect that control to the dmegamemodel
  652. int c = m_ControlInfo.Count();
  653. for ( int i = 0; i < c; ++i )
  654. {
  655. ControlInfo_t &info = m_ControlInfo[i];
  656. if ( info.m_bIsStereo )
  657. {
  658. BuildStereoFlexControllerOps( pAnimationSet, pGameModel, pChannelsClip, info );
  659. }
  660. else
  661. {
  662. BuildFlexControllerOps( pGameModel, pChannelsClip, info, CONTROL_VALUE );
  663. }
  664. if ( info.m_bIsMulti )
  665. {
  666. BuildFlexControllerOps( pGameModel, pChannelsClip, info, CONTROL_MULTILEVEL );
  667. }
  668. }
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Initializes the fields of a flex control
  672. //-----------------------------------------------------------------------------
  673. void CFlexControlBuilder::InitializeFlexControl( ControlInfo_t &info )
  674. {
  675. CDmElement *pControl = info.m_pControl;
  676. // Remove these, if they exist...
  677. for ( int i = 0; i < CONTROL_CHANNEL_ATTRIBUTE_COUNT; ++i )
  678. {
  679. pControl->RemoveAttribute( s_pChannelControls[i] );
  680. }
  681. // Force these to always be up-to-date
  682. pControl->SetValue< bool >( "combo", info.m_bIsStereo );
  683. pControl->SetValue< bool >( "multi", info.m_bIsMulti );
  684. pControl->SetValue< float >( "defaultValue", info.m_pDefaultValue[CONTROL_VALUE] );
  685. pControl->SetValue< float >( "defaultBalance", info.m_pDefaultValue[CONTROL_BALANCE] );
  686. pControl->SetValue< float >( "defaultMultilevel", info.m_pDefaultValue[CONTROL_MULTILEVEL] );
  687. // These can keep their value if they already exist
  688. pControl->InitValue< float >( "value", info.m_pDefaultValue[CONTROL_VALUE] );
  689. if ( info.m_bIsStereo )
  690. {
  691. pControl->InitValue< float >( "balance", info.m_pDefaultValue[CONTROL_BALANCE] );
  692. }
  693. else
  694. {
  695. pControl->RemoveAttribute( "balance" );
  696. }
  697. if ( info.m_bIsMulti )
  698. {
  699. pControl->InitValue< float >( "multilevel", info.m_pDefaultValue[CONTROL_MULTILEVEL] );
  700. }
  701. else
  702. {
  703. pControl->RemoveAttribute( "multilevel" );
  704. }
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Creates all controls for flexes
  708. //-----------------------------------------------------------------------------
  709. void CFlexControlBuilder::CreateFlexControls( CDmeAnimationSet *pAnimationSet )
  710. {
  711. // Create a facial control for all input controls
  712. int c = m_ControlInfo.Count();
  713. for ( int i = 0; i < c; ++i )
  714. {
  715. ControlInfo_t &info = m_ControlInfo[i];
  716. // Check to see if the animation set already has the control
  717. info.m_pControl = pAnimationSet->FindOrAddControl( info.m_pControlName );
  718. // Now initialize the fields of the flex control
  719. InitializeFlexControl( info );
  720. }
  721. }
  722. //-----------------------------------------------------------------------------
  723. // Attaches existing logs and sets default values for logs
  724. //-----------------------------------------------------------------------------
  725. void CFlexControlBuilder::SetupLogs( CDmeChannelsClip *pChannelsClip, bool bUseExistingLogs )
  726. {
  727. DmeTime_t targetOffset;
  728. double flTargetScale;
  729. ComputeChannelTimeTransform( &targetOffset, &flTargetScale, pChannelsClip );
  730. double flOOTargetScale = ( flTargetScale != 0.0 ) ? 1.0 / flTargetScale : 1.0;
  731. // Build the infrastructure of the ops that connect that control to the dmegamemodel
  732. int c = m_ControlInfo.Count();
  733. for ( int i = 0; i < c; ++i )
  734. {
  735. ControlInfo_t &info = m_ControlInfo[i];
  736. for ( int j = 0; j < CONTROL_FIELD_COUNT; ++j )
  737. {
  738. // Can happen for non-multi or non-stereo controls
  739. if ( !info.m_ppControlChannel[j] )
  740. continue;
  741. // Replace the existing log if we need to
  742. CDmeFloatLog *pFloatLog = CastElement< CDmeFloatLog >( info.m_ppControlChannel[j]->GetLog() );
  743. if ( bUseExistingLogs && info.m_pExistingLog[j].m_pLog )
  744. {
  745. info.m_ppControlChannel[j]->SetLog( info.m_pExistingLog[j].m_pLog );
  746. DestroyElement( pFloatLog );
  747. pFloatLog = info.m_pExistingLog[j].m_pLog;
  748. // Apply transform to get the log into the space of the current channel
  749. double flTotalScale = info.m_pExistingLog[j].m_flGlobalScale * flOOTargetScale;
  750. DmeTime_t totalOffset = info.m_pExistingLog[j].m_GlobalOffset - targetOffset;
  751. totalOffset.SetSeconds( totalOffset.GetSeconds() * flOOTargetScale );
  752. pFloatLog->ScaleBiasKeyTimes( flTotalScale, totalOffset );
  753. }
  754. // Set the default value for this log
  755. pFloatLog->SetDefaultValue( info.m_pDefaultValue[j] );
  756. }
  757. }
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Main entry point for creating flex animation set controls
  761. //-----------------------------------------------------------------------------
  762. void CFlexControlBuilder::CreateAnimationSetControls( CDmeFilmClip *pMovie, CDmeAnimationSet *pAnimationSet,
  763. CDmeGameModel *pGameModel, CDmeFilmClip *pSourceClip, CDmeChannelsClip *pDestClip, bool bUseExistingLogs )
  764. {
  765. m_pMovie = pMovie;
  766. FixupExistingFlexControlLogList( pSourceClip, pGameModel );
  767. // First, look at the current mdl and determine what are its low-level flexcontrollers
  768. // [these are the outputs eventually driven by the animation set controls]
  769. BuildDesiredFlexControlList( pGameModel );
  770. // Next, based on the list of low-level flexcontrollers, determine a high-level set of input controls
  771. BuildDesiredControlList( pGameModel );
  772. // Next look at what the animation set currently thinks are the input controls + low-level flexcontrollers
  773. // and remove the unused ones
  774. RemoveUnusedExistingFlexControllers( pGameModel );
  775. RemoveUnusedControlsAndChannels( pAnimationSet, pDestClip );
  776. if ( bUseExistingLogs )
  777. {
  778. // Look at the current input controls + low-level flexcontrollers
  779. // and grab logs that drive them so we can apply them to the new controls
  780. BuildExistingFlexControlLogList( pSourceClip, pGameModel );
  781. }
  782. // Create the input controls we decided we needed in BuildDesiredControlList
  783. CreateFlexControls( pAnimationSet );
  784. // Build channels + control logis attaching the input controls to the low level flex controls
  785. AttachControlsToGameModel( pAnimationSet, pGameModel, pDestClip );
  786. // Attach existing logs to the new input controls created in CreateFlexControls
  787. SetupLogs( pDestClip, bUseExistingLogs );
  788. }
  789. //-----------------------------------------------------------------------------
  790. // Initialize default global flex controller
  791. //-----------------------------------------------------------------------------
  792. void SetupDefaultFlexController()
  793. {
  794. g_pGlobalFlexController = &s_GlobalFlexController;
  795. }