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.

862 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/importintovcd.h"
  7. #include "movieobjects/movieobjects.h"
  8. #include "tier3/scenetokenprocessor.h"
  9. #include "choreoscene.h"
  10. #include "choreoactor.h"
  11. #include "choreochannel.h"
  12. #include "choreoevent.h"
  13. #include "tier2/p4helpers.h"
  14. #include "tier1/utlbuffer.h"
  15. #include "tier3/tier3.h"
  16. #include "datacache/imdlcache.h"
  17. #include "filesystem.h"
  18. #include "studio.h"
  19. //-----------------------------------------------------------------------------
  20. // Helper wrapper class for log layers (necessary to avoid movieobjects dependence)
  21. //-----------------------------------------------------------------------------
  22. class CDmeLogLayerHelper
  23. {
  24. public:
  25. CDmeLogLayerHelper( CDmElement *pLogLayer, int nDefaultCurveType );
  26. // Finds a key
  27. int FindKey( int nTime ) const;
  28. // Gets a value at a particular time
  29. float GetValue( int nTime ) const;
  30. // Inserts keys
  31. void AddToTail( int nTime, float flValue, int nCurveType );
  32. void InsertAfter( int nAfter, int nTime, float flValue, int nCurveType );
  33. int InsertKey( int nTime, float flValue, int nCurveType );
  34. // Simplifies the curve
  35. void Simplify( float flThreshhold );
  36. void SetCurveType( int nKey, int nCurveType );
  37. // Total simplified points
  38. static int TotalRemovedPoints();
  39. private:
  40. void CurveSimplify_R( float flThreshold, int nStartPoint, int nEndPoint, CDmeLogLayerHelper *pDest );
  41. // Computes the total error
  42. float ComputeTotalError( CDmeLogLayerHelper *pDest, int nStartPoint, int nEndPoint );
  43. // Select the best fit curve type
  44. void ChooseBestCurveType( int nKey, int nStartPoint, int nEndPoint, CDmeLogLayerHelper *pDest );
  45. // Compute first + second derivatives of data
  46. void ComputeDerivates( float *pSlope, float *pAccel, int nPoint, CDmeLogLayerHelper *pDest );
  47. CDmElement *m_pLogLayer;
  48. CDmrArray<int> m_times;
  49. CDmrArray<float> m_values;
  50. CDmrArray<int> m_curvetypes;
  51. int m_nDefaultCurveType;
  52. static int s_nTotalRemovedPoints;
  53. };
  54. //-----------------------------------------------------------------------------
  55. // Total simplified points
  56. //-----------------------------------------------------------------------------
  57. int CDmeLogLayerHelper::s_nTotalRemovedPoints = 0;
  58. int CDmeLogLayerHelper::TotalRemovedPoints()
  59. {
  60. return s_nTotalRemovedPoints;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Constructor
  64. //-----------------------------------------------------------------------------
  65. CDmeLogLayerHelper::CDmeLogLayerHelper( CDmElement *pLogLayer, int nDefaultCurveType ) :
  66. m_pLogLayer( pLogLayer ), m_times( pLogLayer, "times", true ),
  67. m_values( pLogLayer, "values", true ), m_curvetypes( pLogLayer, "curvetypes", true )
  68. {
  69. m_nDefaultCurveType = nDefaultCurveType;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Inserts keys
  73. //-----------------------------------------------------------------------------
  74. void CDmeLogLayerHelper::AddToTail( int nTime, float flValue, int nCurveType )
  75. {
  76. m_times.AddToTail( nTime );
  77. m_values.AddToTail( flValue );
  78. m_curvetypes.AddToTail( nCurveType );
  79. }
  80. void CDmeLogLayerHelper::InsertAfter( int nAfter, int nTime, float flValue, int nCurveType )
  81. {
  82. int nBefore = nAfter + 1;
  83. m_times.InsertBefore( nBefore, nTime );
  84. m_values.InsertBefore( nBefore, flValue );
  85. m_curvetypes.InsertBefore( nBefore, nCurveType );
  86. }
  87. int CDmeLogLayerHelper::InsertKey( int nTime, float flValue, int nCurveType )
  88. {
  89. int nAfter = FindKey( nTime );
  90. InsertAfter( nAfter, nTime, flValue, nCurveType );
  91. return nAfter + 1;
  92. }
  93. void CDmeLogLayerHelper::SetCurveType( int nKey, int nCurveType )
  94. {
  95. m_curvetypes.Set( nKey, nCurveType );
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Finds a key
  99. //-----------------------------------------------------------------------------
  100. int CDmeLogLayerHelper::FindKey( int nTime ) const
  101. {
  102. int tn = m_times.Count();
  103. for ( int ti = tn - 1; ti >= 0; --ti )
  104. {
  105. if ( nTime >= m_times[ ti ] )
  106. return ti;
  107. }
  108. return -1;
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Gets a value at a particular time
  112. //-----------------------------------------------------------------------------
  113. float CDmeLogLayerHelper::GetValue( int nTime ) const
  114. {
  115. int tc = m_times.Count();
  116. Assert( m_values.Count() == tc );
  117. int ti = FindKey( nTime );
  118. if ( ti < 0 )
  119. {
  120. if ( tc > 0 )
  121. return m_values[ 0 ];
  122. return 0.0f;
  123. }
  124. // Early out if we're at the end
  125. if ( ti >= tc - 1 )
  126. return m_values[ ti ];
  127. // Figure out the lerp factor
  128. int nDummy, nInterpolationType;
  129. int nCurveType = m_curvetypes.Count() ? m_curvetypes[ti] : m_nDefaultCurveType;
  130. Interpolator_CurveInterpolatorsForType( nCurveType, nInterpolationType, nDummy );
  131. Vector vecOutput;
  132. Vector vecArg1( 0.0f, m_values[ti], 0.0f );
  133. Vector vecArg2( 1.0f, m_values[ti+1], 0.0f );
  134. float t = (float)( nTime - m_times[ti] ) / (float)( m_times[ti+1] - m_times[ti] );
  135. Interpolator_CurveInterpolate( nInterpolationType, vecArg1, vecArg1, vecArg2, vecArg2, t, vecOutput );
  136. return vecOutput.y;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Computes the total error
  140. //-----------------------------------------------------------------------------
  141. float CDmeLogLayerHelper::ComputeTotalError( CDmeLogLayerHelper *pDest, int nStartPoint, int nEndPoint )
  142. {
  143. float flTotalDistance = 0.0f;
  144. for ( int i = nStartPoint; i <= nEndPoint; ++i )
  145. {
  146. float flCheck = m_values[i];
  147. float flCheck2 = pDest->GetValue( m_times[i] );
  148. float flDistance = fabs( flCheck2 - flCheck );
  149. flTotalDistance += flDistance;
  150. }
  151. return flTotalDistance;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Select the best fit curve type
  155. //-----------------------------------------------------------------------------
  156. static int s_nInterpTypes[] =
  157. {
  158. INTERPOLATE_LINEAR_INTERP,
  159. INTERPOLATE_EASE_INOUT,
  160. // INTERPOLATE_EASE_IN,
  161. // INTERPOLATE_EASE_OUT,
  162. // INTERPOLATE_EXPONENTIAL_DECAY,
  163. // INTERPOLATE_HOLD,
  164. -1,
  165. };
  166. void CDmeLogLayerHelper::ChooseBestCurveType( int nKey, int nStartPoint, int nEndPoint, CDmeLogLayerHelper *pDest )
  167. {
  168. return;
  169. float flMinError = FLT_MAX;
  170. int nBestInterpType = -1;
  171. for ( int i = 0; s_nInterpTypes[i] >= 0; ++i )
  172. {
  173. pDest->SetCurveType( nKey, MAKE_CURVE_TYPE( s_nInterpTypes[i], s_nInterpTypes[i] ) );
  174. float flError = ComputeTotalError( pDest, nStartPoint, nEndPoint );
  175. if ( flMinError > flError )
  176. {
  177. nBestInterpType = s_nInterpTypes[i];
  178. flMinError = flError;
  179. }
  180. }
  181. Assert( nBestInterpType >= 0 );
  182. pDest->SetCurveType( nKey, MAKE_CURVE_TYPE( nBestInterpType, nBestInterpType ) );
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Compute first + second derivatives of data
  186. //-----------------------------------------------------------------------------
  187. void CDmeLogLayerHelper::ComputeDerivates( float *pSlope, float *pAccel, int nPoint, CDmeLogLayerHelper *pDest )
  188. {
  189. // Central difference, assume linear slope between points.
  190. // Find neighboring point with minimum distance
  191. bool bLeftEdge = ( nPoint == 0 );
  192. bool bRightEdge = ( nPoint == m_times.Count() - 1 );
  193. int nTime = m_times[nPoint];
  194. int nPrevTime = ( !bLeftEdge ) ? m_times[ nPoint - 1 ] : nTime - 1000;
  195. int nNextTime = ( !bRightEdge ) ? m_times[ nPoint + 1 ] : nTime + 1000;
  196. float flPrevPoint, flNextPoint;
  197. if ( nTime - nPrevTime < nNextTime - nTime )
  198. {
  199. // prev point is closer
  200. flPrevPoint = ( !bLeftEdge ) ? m_values[ nPoint - 1 ] : m_values[ nPoint ];
  201. nNextTime = nTime + ( nTime - nPrevTime );
  202. flNextPoint = GetValue( nNextTime );
  203. }
  204. else
  205. {
  206. // next point is closer
  207. flNextPoint = ( !bRightEdge ) ? m_values[ nPoint + 1 ] : m_values[ nPoint ];
  208. nPrevTime = nTime - ( nNextTime - nTime );
  209. flPrevPoint = GetValue( nPrevTime );
  210. }
  211. // Central difference: slope = ( vnext - vprev ) / ( tnext - tprev );
  212. // accel = ( vnext - 2 * vcurr + vprev ) / ( 0.5 * ( tnext - tprev ) )^2
  213. float flCurrPoint = m_values[nPoint];
  214. flPrevPoint -= pDest->GetValue( nPrevTime );
  215. flCurrPoint -= pDest->GetValue( nTime );
  216. flNextPoint -= pDest->GetValue( nNextTime );
  217. float flDeltaTime = DMETIME_TO_SECONDS( nTime - nPrevTime );
  218. *pSlope = ( flNextPoint - flPrevPoint ) / ( 2.0f * flDeltaTime );
  219. *pAccel = ( flNextPoint - 2 * flCurrPoint + flPrevPoint ) / ( flDeltaTime * flDeltaTime );
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Implementation of Douglas-Peucker curve simplification routine
  223. // (hacked to only care about error against original curve (sort of 1D)
  224. //-----------------------------------------------------------------------------
  225. void CDmeLogLayerHelper::CurveSimplify_R( float flThreshold, int nStartPoint, int nEndPoint, CDmeLogLayerHelper *pDest )
  226. {
  227. if ( nEndPoint <= nStartPoint + 1 )
  228. return;
  229. int nMaxPoint = nStartPoint;
  230. float flMaxDistance = 0.0f;
  231. for ( int i = nStartPoint + 1 ; i < nEndPoint; ++i )
  232. {
  233. float flCheck = m_values[i];
  234. float flCheck2 = pDest->GetValue( m_times[i] );
  235. float flDistance = fabs( flCheck2 - flCheck );
  236. if ( flDistance < flMaxDistance )
  237. continue;
  238. nMaxPoint = i;
  239. flMaxDistance = flDistance;
  240. }
  241. /*
  242. float flMaxAccel = 0.0f;
  243. for ( int i = nStartPoint + 1 ; i < nEndPoint; ++i )
  244. {
  245. float flSlope, flAccel;
  246. ComputeDerivates( &flSlope, &flAccel, i, pDest );
  247. flAccel = fabs( flAccel );
  248. if ( flAccel < flMaxAccel )
  249. continue;
  250. nMaxPoint = i;
  251. flMaxAccel = flAccel;
  252. }
  253. */
  254. if ( flMaxDistance > flThreshold )
  255. {
  256. int nKey = pDest->InsertKey( m_times[ nMaxPoint ], m_values[ nMaxPoint ], m_nDefaultCurveType );
  257. Assert( nKey != 0 );
  258. ChooseBestCurveType( nKey-1, nStartPoint, nMaxPoint, pDest );
  259. ChooseBestCurveType( nKey, nMaxPoint, nEndPoint, pDest );
  260. CurveSimplify_R( flThreshold, nStartPoint, nMaxPoint, pDest );
  261. CurveSimplify_R( flThreshold, nMaxPoint, nEndPoint, pDest );
  262. }
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Simplifies the curve
  266. //-----------------------------------------------------------------------------
  267. void CDmeLogLayerHelper::Simplify( float flThreshhold )
  268. {
  269. int nFirstKey, nLastKey;
  270. int nKeys = m_values.Count();
  271. if ( nKeys <= 1 )
  272. return;
  273. for ( nFirstKey = 1; nFirstKey < nKeys; ++nFirstKey )
  274. {
  275. // FIXME: Should we use a tolerance check here?
  276. if ( m_values[ nFirstKey ] != m_values[ nFirstKey - 1 ] )
  277. break;
  278. }
  279. --nFirstKey;
  280. for ( nLastKey = nKeys; --nLastKey >= 1; )
  281. {
  282. // FIXME: Should we use a tolerance check here?
  283. if ( m_values[ nLastKey ] != m_values[ nLastKey - 1 ] )
  284. break;
  285. }
  286. if ( nLastKey <= nFirstKey )
  287. {
  288. m_times.RemoveMultiple( 1, nKeys - 1 );
  289. m_values.RemoveMultiple( 1, nKeys - 1 );
  290. s_nTotalRemovedPoints += nKeys - 1;
  291. return;
  292. }
  293. CDmElement *pTemp = CreateElement< CDmElement >( "simplified" );
  294. CDmeLogLayerHelper destLayer( pTemp, m_nDefaultCurveType );
  295. destLayer.AddToTail( m_times[nFirstKey], m_values[nFirstKey], m_nDefaultCurveType );
  296. destLayer.AddToTail( m_times[nLastKey], m_values[nLastKey], m_nDefaultCurveType );
  297. // Recursively finds the point with the largest error from the "simplified curve"
  298. // and subdivides the problem on both sides until the largest delta from the simplified
  299. // curve is less than the tolerance
  300. CurveSimplify_R( flThreshhold, nFirstKey, nLastKey, &destLayer );
  301. m_times.CopyArray( destLayer.m_times.Base(), destLayer.m_times.Count() );
  302. m_values.CopyArray( destLayer.m_values.Base(), destLayer.m_values.Count() );
  303. m_curvetypes.CopyArray( destLayer.m_curvetypes.Base(), destLayer.m_curvetypes.Count() );
  304. DestroyElement( pTemp );
  305. s_nTotalRemovedPoints += nKeys - m_times.Count();
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Finds or adds actors, channels
  309. //-----------------------------------------------------------------------------
  310. static CChoreoActor* FindOrAddActor( CChoreoScene *pScene, const char *pActorName, const char *pActorModel )
  311. {
  312. CChoreoActor *a = pScene->FindActor( pActorName );
  313. if ( !a )
  314. {
  315. a = pScene->AllocActor();
  316. Assert( a );
  317. a->SetName( pActorName );
  318. a->SetActive( true );
  319. a->SetFacePoserModelName( pActorModel );
  320. }
  321. return a;
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Finds animation events
  325. //-----------------------------------------------------------------------------
  326. static CChoreoEvent* FindOrAddAnimationEvent( CChoreoScene *pScene, CChoreoActor *pActor )
  327. {
  328. int nEventCount = pScene->GetNumEvents();
  329. for ( int i = 0; i < nEventCount; ++i )
  330. {
  331. CChoreoEvent* pEvent = pScene->GetEvent(i);
  332. if ( pEvent->GetActor() != pActor )
  333. continue;
  334. if ( pEvent->GetType() != CChoreoEvent::FLEXANIMATION )
  335. continue;
  336. return pEvent;
  337. }
  338. // Allocate new channel
  339. CChoreoChannel *pChannel = pScene->AllocChannel();
  340. pChannel->SetName( "imported_flex" );
  341. pChannel->SetActor( pActor );
  342. pChannel->SetActive( true );
  343. pActor->AddChannel( pChannel );
  344. // Allocate choreo event
  345. CChoreoEvent *pEvent = pScene->AllocEvent();
  346. pEvent->SetName( pActor->GetName() );
  347. pEvent->SetType( CChoreoEvent::FLEXANIMATION );
  348. pEvent->SetActor( pActor );
  349. pEvent->SetChannel( pChannel );
  350. pEvent->SetActive( true );
  351. pChannel->AddEvent( pEvent );
  352. return pEvent;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Finds sound events
  356. //-----------------------------------------------------------------------------
  357. static CChoreoEvent* FindOrAddSoundEvent( CChoreoScene *pScene, CChoreoActor *pActor, const char *pEventName )
  358. {
  359. int nEventCount = pScene->GetNumEvents();
  360. for ( int i = 0; i < nEventCount; ++i )
  361. {
  362. CChoreoEvent* pEvent = pScene->GetEvent(i);
  363. if ( pEvent->GetActor() != pActor )
  364. continue;
  365. if ( pEvent->GetType() != CChoreoEvent::SPEAK )
  366. continue;
  367. if ( Q_stricmp( pEvent->GetName(), pEventName ) )
  368. continue;
  369. return pEvent;
  370. }
  371. // Allocate new channel
  372. CChoreoChannel *pChannel = pScene->AllocChannel();
  373. pChannel->SetName( "imported sounds" );
  374. pChannel->SetActor( pActor );
  375. pChannel->SetActive( true );
  376. pActor->AddChannel( pChannel );
  377. // Allocate sound event
  378. CChoreoEvent *pEvent = pScene->AllocEvent();
  379. pEvent->SetName( pEventName );
  380. pEvent->SetType( CChoreoEvent::SPEAK );
  381. pEvent->SetActor( pActor );
  382. pEvent->SetChannel( pChannel );
  383. pEvent->SetActive( true );
  384. pChannel->AddEvent( pEvent );
  385. return pEvent;
  386. }
  387. static CFlexAnimationTrack *FindOrCreateTrack( CChoreoEvent *pEvent, const char *pFlexControllerName )
  388. {
  389. CFlexAnimationTrack *pTrack = pEvent->FindTrack( pFlexControllerName );
  390. if ( pTrack )
  391. {
  392. pTrack->Clear();
  393. }
  394. else
  395. {
  396. pTrack = pEvent->AddTrack( pFlexControllerName );
  397. pTrack->SetTrackActive( true );
  398. }
  399. pTrack->SetMin( 0.0f );
  400. pTrack->SetMax( 1.0f );
  401. pTrack->SetInverted( false );
  402. return pTrack;
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Returns flex controller ranges
  406. //-----------------------------------------------------------------------------
  407. void GetStereoFlexControllerRange( float *pMin, float *pMax, studiohdr_t *pStudioHdr, const char *pFlexName )
  408. {
  409. char pRightBuf[MAX_PATH];
  410. char pLeftBuf[MAX_PATH];
  411. Q_snprintf( pRightBuf, sizeof(pRightBuf), "right_%s", pFlexName );
  412. Q_snprintf( pLeftBuf, sizeof(pLeftBuf), "left_%s", pFlexName );
  413. for ( LocalFlexController_t i = LocalFlexController_t(0); i < pStudioHdr->numflexcontrollers; ++i )
  414. {
  415. mstudioflexcontroller_t *pFlex = pStudioHdr->pFlexcontroller( i );
  416. const char *pFlexControllerName = pFlex->pszName();
  417. if ( !Q_stricmp( pFlexControllerName, pFlexName ) )
  418. {
  419. *pMin = pFlex->min;
  420. *pMax = pFlex->max;
  421. return;
  422. }
  423. // FIXME: Probably want to get the left + right controller + find the min and max of each, but this is unnecessary.
  424. if ( !Q_stricmp( pFlexControllerName, pRightBuf ) )
  425. {
  426. *pMin = pFlex->min;
  427. *pMax = pFlex->max;
  428. return;
  429. }
  430. }
  431. *pMin = 0.0f;
  432. *pMax = 1.0f;
  433. }
  434. void GetFlexControllerRange( float *pMin, float *pMax, studiohdr_t *pStudioHdr, const char *pFlexName )
  435. {
  436. for ( LocalFlexController_t i = LocalFlexController_t(0); i < pStudioHdr->numflexcontrollers; ++i )
  437. {
  438. mstudioflexcontroller_t *pFlex = pStudioHdr->pFlexcontroller( i );
  439. const char *pFlexControllerName = pFlex->pszName();
  440. if ( !Q_stricmp( pFlexControllerName, pFlexName ) )
  441. {
  442. *pMin = pFlex->min;
  443. *pMax = pFlex->max;
  444. return;
  445. }
  446. }
  447. *pMin = 0.0f;
  448. *pMax = 1.0f;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Imports samples into a track
  452. //-----------------------------------------------------------------------------
  453. void ImportSamplesIntoTrack( CFlexAnimationTrack *pTrack, CDmElement *pLog, int nSampleType, int nTimeOffset, const ImportVCDInfo_t& info )
  454. {
  455. CDmrArray<int> times( pLog, "times" );
  456. CDmrArray<float> values( pLog, "values" );
  457. // Add the samples
  458. int nSampleCount = times.Count();
  459. if ( nSampleCount == 0 )
  460. return;
  461. int nDefaultCurveType = MAKE_CURVE_TYPE( info.m_nInterpolationType, info.m_nInterpolationType );
  462. if ( info.m_flSimplificationThreshhold > 0.0f )
  463. {
  464. CDmeLogLayerHelper helper( pLog, nDefaultCurveType );
  465. helper.Simplify( info.m_flSimplificationThreshhold );
  466. }
  467. CDmrArray<int> curveTypes( pLog, "curvetypes" );
  468. nSampleCount = times.Count();
  469. bool bHasCurveTypeData = ( curveTypes.Count() > 0 );
  470. for ( int j = 0; j < nSampleCount; ++j )
  471. {
  472. int nCurveType = bHasCurveTypeData ? curveTypes[j] : nDefaultCurveType;
  473. float flValue = values[j];
  474. float flTime = DMETIME_TO_SECONDS( times[j] - nTimeOffset );
  475. CExpressionSample *pSample = pTrack->AddSample( flTime, flValue, nSampleType );
  476. pSample->SetCurveType( nCurveType );
  477. }
  478. if ( nSampleType == 0 )
  479. {
  480. pTrack->SetEdgeActive( true, true );
  481. pTrack->SetEdgeActive( false, true );
  482. int nCurveType0, nCurveType1;
  483. if ( bHasCurveTypeData )
  484. {
  485. nCurveType0 = curveTypes[0];
  486. nCurveType1 = curveTypes[nSampleCount-1];
  487. }
  488. else
  489. {
  490. nCurveType0 = nCurveType1 = nDefaultCurveType;
  491. }
  492. pTrack->SetEdgeInfo( true, nCurveType0, values[ 0 ] );
  493. pTrack->SetEdgeInfo( false, nCurveType1, values[ nSampleCount-1 ] );
  494. }
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Imports mono log data into a event, creates a new track if necessary
  498. //-----------------------------------------------------------------------------
  499. void ImportMonoLogDataIntoEvent( studiohdr_t *pStudioHdr, CChoreoEvent *pEvent, const char *pTrackName, CDmElement *pLog, int nTimeOffset, const ImportVCDInfo_t& info )
  500. {
  501. CDmrArray<int> times( pLog, "times" );
  502. if ( times.Count() == 0 )
  503. return;
  504. float flMin, flMax;
  505. GetFlexControllerRange( &flMin, &flMax, pStudioHdr, pTrackName );
  506. CFlexAnimationTrack *pTrack = FindOrCreateTrack( pEvent, pTrackName );
  507. pTrack->Clear();
  508. pTrack->SetComboType( false );
  509. pTrack->SetMin( flMin );
  510. pTrack->SetMax( flMax );
  511. ImportSamplesIntoTrack( pTrack, pLog, 0, nTimeOffset, info );
  512. }
  513. //-----------------------------------------------------------------------------
  514. // Imports stereo log data into a event, creates a new track if necessary
  515. //-----------------------------------------------------------------------------
  516. void ImportStereoLogDataIntoEvent( studiohdr_t *pStudioHdr, CChoreoEvent *pEvent, const char *pTrackName, CDmElement *pValueLog, CDmElement *pBalanceLog, int nTimeOffset, const ImportVCDInfo_t& info )
  517. {
  518. CDmrArray<int> valueTimes( pValueLog, "times" );
  519. CDmrArray<int> balanceTimes( pBalanceLog, "times" );
  520. if ( valueTimes.Count() == 0 && balanceTimes.Count() == 0 )
  521. return;
  522. float flMin, flMax;
  523. GetStereoFlexControllerRange( &flMin, &flMax, pStudioHdr, pTrackName );
  524. CFlexAnimationTrack *pTrack = FindOrCreateTrack( pEvent, pTrackName );
  525. pTrack->Clear();
  526. pTrack->SetComboType( true );
  527. pTrack->SetMin( flMin );
  528. pTrack->SetMax( flMax );
  529. ImportSamplesIntoTrack( pTrack, pValueLog, 0, nTimeOffset, info );
  530. ImportSamplesIntoTrack( pTrack, pBalanceLog, 1, nTimeOffset, info );
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Compute track start, end time
  534. //-----------------------------------------------------------------------------
  535. static int ComputeEventTime( CDmElement *pRoot, CChoreoEvent *pEvent )
  536. {
  537. int nStartTime = INT_MAX;
  538. int nEndTime = INT_MIN;
  539. // Iterate over all elements in the animations attribute; each one refers to a log.
  540. CDmrElementArray<> animations( pRoot, "animations" );
  541. if ( !animations.IsValid() )
  542. return 0;
  543. int nCount = animations.Count();
  544. for( int i = 0; i < nCount; ++i )
  545. {
  546. CDmElement *pLog = animations[i];
  547. if ( !pLog )
  548. continue;
  549. CDmrArray<int> times( pLog, "times" );
  550. int nSampleCount = times.Count();
  551. if ( nSampleCount == 0 )
  552. continue;
  553. if ( nStartTime > times[0] )
  554. {
  555. nStartTime = times[0];
  556. }
  557. if ( nEndTime < times[nSampleCount-1] )
  558. {
  559. nEndTime = times[nSampleCount-1];
  560. }
  561. }
  562. pEvent->SetStartTime( DMETIME_TO_SECONDS( nStartTime ) );
  563. pEvent->SetEndTime( DMETIME_TO_SECONDS( nEndTime ) );
  564. return nStartTime;
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Main entry point for importing animations
  568. //-----------------------------------------------------------------------------
  569. void ImportAnimations( CDmElement *pRoot, CChoreoScene *pChoreoScene, CChoreoActor *pActor, studiohdr_t *pStudioHdr, const ImportVCDInfo_t& info )
  570. {
  571. CChoreoEvent *pEvent = FindOrAddAnimationEvent( pChoreoScene, pActor );
  572. pEvent->SetDefaultCurveType( MAKE_CURVE_TYPE( info.m_nInterpolationType, info.m_nInterpolationType ) );
  573. int nTimeOffset = ComputeEventTime( pRoot, pEvent );
  574. // Iterate over all elements in the animations attribute; each one refers to a log.
  575. CDmrElementArray<> animations( pRoot, "animations" );
  576. if ( !animations.IsValid() )
  577. return;
  578. int nCount = animations.Count();
  579. for( int i = 0; i < nCount; ++i )
  580. {
  581. CDmElement *pLog = animations[i];
  582. if ( !pLog )
  583. continue;
  584. const char *pLogName = pLog->GetName();
  585. // Balance is done at the same time as value
  586. if ( StringHasPrefix( pLogName, "balance_" ) )
  587. continue;
  588. if ( StringHasPrefix( pLogName, "value_" ) )
  589. {
  590. if ( i == nCount - 1 )
  591. continue;
  592. char pBalanceName[256];
  593. Q_snprintf( pBalanceName, sizeof(pBalanceName), "balance_%s", pLogName + 6 );
  594. CDmElement *pBalanceLog = animations[i+1];
  595. if ( !Q_stricmp( pBalanceName, pBalanceLog->GetName() ) )
  596. {
  597. ++i;
  598. }
  599. else
  600. {
  601. pBalanceLog = NULL;
  602. }
  603. if ( pBalanceLog )
  604. {
  605. ImportStereoLogDataIntoEvent( pStudioHdr, pEvent, pLogName + 6, pLog, pBalanceLog, nTimeOffset, info );
  606. }
  607. }
  608. else
  609. {
  610. ImportMonoLogDataIntoEvent( pStudioHdr, pEvent, pLogName, pLog, nTimeOffset, info );
  611. }
  612. }
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Main entry point for importing sounds
  616. //-----------------------------------------------------------------------------
  617. void ImportSounds( CDmElement *pRoot, CChoreoScene *pChoreoScene, CChoreoActor *pActor, const ImportVCDInfo_t& info )
  618. {
  619. // Iterate over all element in the sound attribute; each one refers to a sound
  620. CDmrElementArray<> sounds( pRoot, "sounds" );
  621. if ( !sounds.IsValid() )
  622. return;
  623. int nCount = sounds.Count();
  624. for( int i = 0; i < nCount; ++i )
  625. {
  626. CDmElement *pSound = sounds[i];
  627. if ( !pSound )
  628. continue;
  629. const char *pEventName = pSound->GetName();
  630. CChoreoEvent *pEvent = FindOrAddSoundEvent( pChoreoScene, pActor, pEventName );
  631. int nStart = pSound->GetValue<int>( "start" );
  632. int nEnd = pSound->GetValue<int>( "end" );
  633. const char *pGameSound = pSound->GetValueString( "gamesound" );
  634. pEvent->SetStartTime( DMETIME_TO_SECONDS( nStart ) );
  635. pEvent->SetEndTime( DMETIME_TO_SECONDS( nEnd ) );
  636. pEvent->SetParameters( pGameSound );
  637. pEvent->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  638. }
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Main entry point for importing a .fac file into a .vcd file
  642. //-----------------------------------------------------------------------------
  643. bool ImportLogsIntoVCD( const char *pFacFullPath, CChoreoScene *pChoreoScene, const ImportVCDInfo_t& info )
  644. {
  645. CDmElement *pRoot;
  646. DmFileId_t id = g_pDataModel->RestoreFromFile( pFacFullPath, NULL, NULL, &pRoot, CR_FORCE_COPY );
  647. if ( id == DMFILEID_INVALID )
  648. {
  649. Warning( "Unable to load file %s\n", pFacFullPath );
  650. return false;
  651. }
  652. pChoreoScene->IgnorePhonemes( info.m_bIgnorePhonemes );
  653. // Create the actor in the scene
  654. const char *pActorName = pRoot->GetName();
  655. const char *pActorModel = pRoot->GetValueString( "gamemodel" );
  656. MDLHandle_t hMDL = g_pMDLCache->FindMDL( pActorModel );
  657. if ( hMDL == MDLHANDLE_INVALID )
  658. {
  659. Warning( "vcdimport: Model %s doesn't exist!\n", pActorModel );
  660. return false;
  661. }
  662. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( hMDL );
  663. if ( !pStudioHdr || g_pMDLCache->IsErrorModel( hMDL ) )
  664. {
  665. Warning( "vcdimport: Model %s doesn't exist!\n", pActorModel );
  666. return false;
  667. }
  668. CChoreoActor *pActor = FindOrAddActor( pChoreoScene, pActorName, pActorModel );
  669. ImportAnimations( pRoot, pChoreoScene, pActor, pStudioHdr, info );
  670. ImportSounds( pRoot, pChoreoScene, pActor, info );
  671. DestroyElement( pRoot, TD_DEEP );
  672. return true;
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Main entry point for importing a .fac file into a .vcd file
  676. //-----------------------------------------------------------------------------
  677. bool ImportLogsIntoVCD( const char *pFacFullPath, const char *pVCDInFullPath, const char *pVCDOutPath, const ImportVCDInfo_t& info )
  678. {
  679. CUtlBuffer buf;
  680. if ( !g_pFullFileSystem->ReadFile( pVCDInFullPath, NULL, buf ) )
  681. {
  682. Warning( "Unable to load file %s\n", pVCDInFullPath );
  683. return false;
  684. }
  685. SetTokenProcessorBuffer( (char *)buf.Base() );
  686. CChoreoScene *pScene = ChoreoLoadScene( pVCDInFullPath, NULL, GetTokenProcessor(), NULL );
  687. if ( !pScene )
  688. {
  689. Warning( "Unable to parse file %s\n", pVCDInFullPath );
  690. return false;
  691. }
  692. bool bOk = ImportLogsIntoVCD( pFacFullPath, pScene, info );
  693. if ( !bOk )
  694. return false;
  695. Msg( "Removed %d samples\n", CDmeLogLayerHelper::TotalRemovedPoints() );
  696. char pTemp[MAX_PATH];
  697. if ( !Q_IsAbsolutePath( pVCDOutPath ) )
  698. {
  699. g_pFullFileSystem->RelativePathToFullPath( pVCDOutPath, NULL, pTemp, sizeof(pTemp) );
  700. if ( !Q_IsAbsolutePath( pTemp ) )
  701. {
  702. char pDir[MAX_PATH];
  703. if ( g_pFullFileSystem->GetCurrentDirectory( pDir, sizeof(pDir) ) )
  704. {
  705. Q_ComposeFileName( pDir, pVCDOutPath, pTemp, sizeof(pTemp) );
  706. pVCDOutPath = pTemp;
  707. }
  708. }
  709. else
  710. {
  711. pVCDOutPath = pTemp;
  712. }
  713. }
  714. CP4AutoEditFile checkout( pVCDOutPath );
  715. return pScene->SaveToFile( pVCDOutPath );
  716. }