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.

563 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <assert.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include "choreochannel.h"
  12. #include "choreoevent.h"
  13. #include "choreoscene.h"
  14. #include "utlrbtree.h"
  15. #include "tier1/utlbuffer.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. //-----------------------------------------------------------------------------
  19. // Purpose:
  20. //-----------------------------------------------------------------------------
  21. CChoreoChannel::CChoreoChannel( void )
  22. {
  23. Init();
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. // Input : *name -
  28. //-----------------------------------------------------------------------------
  29. CChoreoChannel::CChoreoChannel(const char *name )
  30. {
  31. Init();
  32. SetName( name );
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Purpose:
  36. // Assignment
  37. // Input : src -
  38. //-----------------------------------------------------------------------------
  39. CChoreoChannel& CChoreoChannel::operator=( const CChoreoChannel& src )
  40. {
  41. m_bActive = src.m_bActive;
  42. Q_strncpy( m_szName, src.m_szName, sizeof( m_szName ) );
  43. for ( int i = 0; i < src.m_Events.Size(); i++ )
  44. {
  45. CChoreoEvent *e = src.m_Events[ i ];
  46. CChoreoEvent *newEvent = new CChoreoEvent( e->GetScene() );
  47. *newEvent = *e;
  48. AddEvent( newEvent );
  49. newEvent->SetChannel( this );
  50. newEvent->SetActor( m_pActor );
  51. }
  52. return *this;
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose:
  56. // Input : *name -
  57. //-----------------------------------------------------------------------------
  58. void CChoreoChannel::SetName( const char *name )
  59. {
  60. assert( Q_strlen( name ) < MAX_CHANNEL_NAME );
  61. Q_strncpy( m_szName, name, sizeof( m_szName ) );
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose:
  65. // Output : const char
  66. //-----------------------------------------------------------------------------
  67. const char *CChoreoChannel::GetName( void )
  68. {
  69. return m_szName;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. // Output : int
  74. //-----------------------------------------------------------------------------
  75. int CChoreoChannel::GetNumEvents( void )
  76. {
  77. return m_Events.Size();
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. // Input : event -
  82. // Output : CChoreoEvent
  83. //-----------------------------------------------------------------------------
  84. CChoreoEvent *CChoreoChannel::GetEvent( int event )
  85. {
  86. if ( event < 0 || event >= m_Events.Size() )
  87. {
  88. return NULL;
  89. }
  90. return m_Events[ event ];
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. // Input : *event -
  95. //-----------------------------------------------------------------------------
  96. void CChoreoChannel::AddEvent( CChoreoEvent *event )
  97. {
  98. m_Events.AddToTail( event );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. // Input : *event -
  103. //-----------------------------------------------------------------------------
  104. void CChoreoChannel::RemoveEvent( CChoreoEvent *event )
  105. {
  106. int idx = FindEventIndex( event );
  107. if ( idx == -1 )
  108. return;
  109. m_Events.Remove( idx );
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. void CChoreoChannel::RemoveAllEvents()
  115. {
  116. m_Events.RemoveAll();
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Purpose:
  120. // Input : *event -
  121. // Output : int
  122. //-----------------------------------------------------------------------------
  123. int CChoreoChannel::FindEventIndex( CChoreoEvent *event )
  124. {
  125. for ( int i = 0; i < m_Events.Size(); i++ )
  126. {
  127. if ( event == m_Events[ i ] )
  128. {
  129. return i;
  130. }
  131. }
  132. return -1;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. void CChoreoChannel::Init( void )
  138. {
  139. m_szName[ 0 ] = 0;
  140. SetActor( NULL );
  141. m_bActive = true;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. // Output : CChoreoActor
  146. //-----------------------------------------------------------------------------
  147. CChoreoActor *CChoreoChannel::GetActor( void )
  148. {
  149. return m_pActor;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. // Input : *actor -
  154. //-----------------------------------------------------------------------------
  155. void CChoreoChannel::SetActor( CChoreoActor *actor )
  156. {
  157. m_pActor = actor;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. // Input : active -
  162. //-----------------------------------------------------------------------------
  163. void CChoreoChannel::SetActive( bool active )
  164. {
  165. m_bActive = active;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. // Output : Returns true on success, false on failure.
  170. //-----------------------------------------------------------------------------
  171. bool CChoreoChannel::GetActive( void ) const
  172. {
  173. return m_bActive;
  174. }
  175. static bool ChoreEventStartTimeLessFunc( CChoreoEvent * const &p1, CChoreoEvent * const &p2 )
  176. {
  177. CChoreoEvent *e1;
  178. CChoreoEvent *e2;
  179. e1 = const_cast< CChoreoEvent * >( p1 );
  180. e2 = const_cast< CChoreoEvent * >( p2 );
  181. return e1->GetStartTime() < e2->GetStartTime();
  182. }
  183. void CChoreoChannel::ReconcileGestureTimes()
  184. {
  185. // Sort gesture events within channel by starting time
  186. CUtlRBTree< CChoreoEvent * > sortedGestures( 0, 0, ChoreEventStartTimeLessFunc );
  187. int i;
  188. // Sort items
  189. int c = GetNumEvents();
  190. for ( i = 0; i < c; i++ )
  191. {
  192. CChoreoEvent *e = GetEvent( i );
  193. Assert( e );
  194. if ( e->GetType() != CChoreoEvent::GESTURE )
  195. continue;
  196. sortedGestures.Insert( e );
  197. }
  198. // Now walk list of gestures
  199. if ( !sortedGestures.Count() )
  200. return;
  201. CChoreoEvent *previous = NULL;
  202. for ( i = sortedGestures.FirstInorder(); i != sortedGestures.InvalidIndex(); i = sortedGestures.NextInorder( i ) )
  203. {
  204. CChoreoEvent *event = sortedGestures[ i ];
  205. if ( !previous )
  206. {
  207. // event->SetStartTime( 0.0f );
  208. }
  209. else if ( previous->GetSyncToFollowingGesture() )
  210. {
  211. // TODO: ask the sequence for what tags to match
  212. CEventAbsoluteTag *pEntryTag = event->FindEntryTag( CChoreoEvent::PLAYBACK );
  213. CEventAbsoluteTag *pExitTag = previous->FindExitTag( CChoreoEvent::PLAYBACK );
  214. if (pEntryTag && pExitTag)
  215. {
  216. float entryTime = pEntryTag->GetAbsoluteTime( );
  217. // get current decay rate of previous gesture
  218. float duration = previous->GetDuration();
  219. float decayTime = (1.0 - pExitTag->GetPercentage()) * duration;
  220. // adjust the previous gestures end time to current apex + existing decay rate
  221. previous->RescaleGestureTimes( previous->GetStartTime(), entryTime + decayTime, true );
  222. previous->SetEndTime( entryTime + decayTime );
  223. // set the previous gestures end tag to the current apex
  224. pExitTag->SetAbsoluteTime( entryTime );
  225. event->PreventTagOverlap( );
  226. previous->PreventTagOverlap( );
  227. }
  228. // BUG: Tracker 3298: ywb 1/31/04
  229. // I think this fixes the issue with abutting past NULL gestures on paste:
  230. // Here's the bug report:
  231. // -------------------------
  232. // When copying and pasteing posture and gesture clips in face poser the beginings of the clips stretch
  233. // to the begining of the scene even if there is a null gesture in place at the begining.
  234. // -------------------------
  235. /*
  236. else if ( pEntryTag && !Q_stricmp( previous->GetName(), "NULL" ) )
  237. {
  238. // If the previous was a null event, then do a bit of fixup
  239. event->SetStartTime( previous->GetEndTime() );
  240. event->PreventTagOverlap( );
  241. }
  242. */
  243. // The previous event decays from it's end dispaly end time to the current event's display start time
  244. // The next event starts just after the display end time of the previous event
  245. }
  246. previous = event;
  247. }
  248. if ( previous )
  249. {
  250. CChoreoScene *scene = previous->GetScene();
  251. if ( scene )
  252. {
  253. // HACK: Could probably do better by allowing user to drag the blue "end time" bar
  254. //float finish = scene->FindStopTime();
  255. //previous->RescaleGestureTimes( previous->GetStartTime(), finish );
  256. //previous->SetEndTime( finish );
  257. }
  258. }
  259. /*
  260. c = 0;
  261. for ( i = sortedGestures.FirstInorder(); i != sortedGestures.InvalidIndex(); i = sortedGestures.NextInorder( i ) )
  262. {
  263. CChoreoEvent *event = sortedGestures[ i ];
  264. Msg( "event %i start %f disp %f dispend %f end %f\n",
  265. c + 1,
  266. event->GetStartTime( CChoreoEvent::SIMULATION ),
  267. event->GetStartTime( CChoreoEvent::DISPLAY ),
  268. event->GetEndTime( CChoreoEvent::DISPLAY ),
  269. event->GetEndTime( CChoreoEvent::SIMULATION )
  270. );
  271. c++;
  272. }
  273. */
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose:
  277. //-----------------------------------------------------------------------------
  278. void CChoreoChannel::MarkForSaveAll( bool mark )
  279. {
  280. SetMarkedForSave( mark );
  281. int c = GetNumEvents();
  282. for ( int i = 0; i < c; i++ )
  283. {
  284. CChoreoEvent *e = GetEvent( i );
  285. e->SetMarkedForSave( mark );
  286. }
  287. }
  288. struct EventGroup
  289. {
  290. EventGroup() :
  291. timeSortedEvents( 0, 0, ChoreEventStartTimeLessFunc )
  292. {
  293. }
  294. EventGroup( const EventGroup& src )
  295. :
  296. timeSortedEvents( 0, 0, ChoreEventStartTimeLessFunc )
  297. {
  298. timeSortedEvents.RemoveAll();
  299. int i = src.timeSortedEvents.FirstInorder();
  300. while ( i != src.timeSortedEvents.InvalidIndex() )
  301. {
  302. timeSortedEvents.Insert( src.timeSortedEvents[ i ] );
  303. i = src.timeSortedEvents.NextInorder( i );
  304. }
  305. }
  306. EventGroup & operator=( const EventGroup& src )
  307. {
  308. if ( this == &src )
  309. return *this;
  310. timeSortedEvents.RemoveAll();
  311. int i = src.timeSortedEvents.FirstInorder();
  312. while ( i != src.timeSortedEvents.InvalidIndex() )
  313. {
  314. timeSortedEvents.Insert( src.timeSortedEvents[ i ] );
  315. i = src.timeSortedEvents.NextInorder( i );
  316. }
  317. return *this;
  318. }
  319. CUtlRBTree< CChoreoEvent * > timeSortedEvents;
  320. };
  321. // Compute master/slave, count, endtime info for close captioning data
  322. //-----------------------------------------------------------------------------
  323. // Purpose:
  324. //-----------------------------------------------------------------------------
  325. void CChoreoChannel::ReconcileCloseCaption()
  326. {
  327. // Create a dictionary based on the combined token name
  328. CUtlDict< EventGroup, int > validSpeakEventsGroupedByName;
  329. int i;
  330. // Sort items
  331. int c = GetNumEvents();
  332. for ( i = 0; i < c; i++ )
  333. {
  334. CChoreoEvent *e = GetEvent( i );
  335. Assert( e );
  336. if ( e->GetType() != CChoreoEvent::SPEAK )
  337. continue;
  338. CChoreoEvent::CLOSECAPTION type;
  339. type = e->GetCloseCaptionType();
  340. if ( type == CChoreoEvent::CC_DISABLED )
  341. {
  342. e->SetUsingCombinedFile( false );
  343. e->SetRequiredCombinedChecksum( 0 );
  344. e->SetNumSlaves( 0 );
  345. e->SetLastSlaveEndTime( 0.0f );
  346. continue;
  347. }
  348. char const *name = e->GetCloseCaptionToken();
  349. if ( !name || !name[0] )
  350. {
  351. // Fixup invalid slave tag
  352. if ( type == CChoreoEvent::CC_SLAVE )
  353. {
  354. e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  355. e->SetUsingCombinedFile( false );
  356. e->SetRequiredCombinedChecksum( 0 );
  357. e->SetNumSlaves( 0 );
  358. e->SetLastSlaveEndTime( 0.0f );
  359. }
  360. continue;
  361. }
  362. int idx = validSpeakEventsGroupedByName.Find( name );
  363. if ( idx == validSpeakEventsGroupedByName.InvalidIndex() )
  364. {
  365. EventGroup eg;
  366. eg.timeSortedEvents.Insert( e );
  367. validSpeakEventsGroupedByName.Insert( name, eg );
  368. }
  369. else
  370. {
  371. EventGroup & eg = validSpeakEventsGroupedByName[ idx ];
  372. eg.timeSortedEvents.Insert( e );
  373. }
  374. }
  375. c = validSpeakEventsGroupedByName.Count();
  376. // Now walk list of events by group
  377. if ( !c )
  378. {
  379. return;
  380. }
  381. for ( i = 0; i < c; ++i )
  382. {
  383. EventGroup & eg = validSpeakEventsGroupedByName[ i ];
  384. int sortedEventInGroup = eg.timeSortedEvents.Count();
  385. // If there's only one, just mark it valid
  386. if ( sortedEventInGroup <= 1 )
  387. {
  388. CChoreoEvent *e = eg.timeSortedEvents[ 0 ];
  389. Assert( e );
  390. // Make sure it's the master
  391. e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  392. // Since it's by itself, can't be using "combined" file
  393. e->SetUsingCombinedFile( false );
  394. e->SetRequiredCombinedChecksum( 0 );
  395. e->SetNumSlaves( 0 );
  396. e->SetLastSlaveEndTime( 0.0f );
  397. continue;
  398. }
  399. // Okay, read them back in of start time
  400. int j = eg.timeSortedEvents.FirstInorder();
  401. CChoreoEvent *master = NULL;
  402. while ( j != eg.timeSortedEvents.InvalidIndex() )
  403. {
  404. CChoreoEvent *e = eg.timeSortedEvents[ j ];
  405. if ( !master )
  406. {
  407. master = e;
  408. e->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  409. //e->SetUsingCombinedFile( true );
  410. e->SetRequiredCombinedChecksum( 0 );
  411. e->SetNumSlaves( sortedEventInGroup - 1 );
  412. e->SetLastSlaveEndTime( e->GetEndTime() );
  413. }
  414. else
  415. {
  416. // Keep bumping out the end time
  417. master->SetLastSlaveEndTime( e->GetEndTime() );
  418. e->SetCloseCaptionType( CChoreoEvent::CC_SLAVE );
  419. e->SetUsingCombinedFile( master->IsUsingCombinedFile() );
  420. e->SetRequiredCombinedChecksum( 0 );
  421. e->SetLastSlaveEndTime( 0.0f );
  422. }
  423. j = eg.timeSortedEvents.NextInorder( j );
  424. }
  425. }
  426. }
  427. bool CChoreoChannel::GetSortedCombinedEventList( char const *cctoken, CUtlRBTree< CChoreoEvent * >& events )
  428. {
  429. events.RemoveAll();
  430. int i;
  431. // Sort items
  432. int c = GetNumEvents();
  433. for ( i = 0; i < c; i++ )
  434. {
  435. CChoreoEvent *e = GetEvent( i );
  436. Assert( e );
  437. if ( e->GetType() != CChoreoEvent::SPEAK )
  438. continue;
  439. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  440. continue;
  441. // A master with no slaves is not a combined event
  442. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER &&
  443. e->GetNumSlaves() == 0 )
  444. continue;
  445. char const *token = e->GetCloseCaptionToken();
  446. if ( Q_stricmp( token, cctoken ) )
  447. continue;
  448. events.Insert( e );
  449. }
  450. return ( events.Count() > 0 ) ? true : false;
  451. }
  452. void CChoreoChannel::SaveToBuffer( CUtlBuffer& buf, CChoreoScene *pScene, IChoreoStringPool *pStringPool )
  453. {
  454. buf.PutShort( pStringPool->FindOrAddString( GetName() ) );
  455. int c = GetNumEvents();
  456. Assert( c <= 255 );
  457. buf.PutUnsignedChar( c );
  458. for ( int i = 0; i < c; i++ )
  459. {
  460. CChoreoEvent *e = GetEvent( i );
  461. Assert( e );
  462. e->SaveToBuffer( buf, pScene, pStringPool );
  463. }
  464. buf.PutChar( GetActive() ? 1 : 0 );
  465. }
  466. bool CChoreoChannel::RestoreFromBuffer( CUtlBuffer& buf, CChoreoScene *pScene, CChoreoActor *pActor, IChoreoStringPool *pStringPool )
  467. {
  468. char sz[ 256 ];
  469. pStringPool->GetString( buf.GetShort(), sz, sizeof( sz ) );
  470. SetName( sz );
  471. int numEvents = (int)buf.GetUnsignedChar();
  472. for ( int i = 0 ; i < numEvents; ++i )
  473. {
  474. CChoreoEvent *e = pScene->AllocEvent();
  475. if ( e->RestoreFromBuffer( buf, pScene, pStringPool ) )
  476. {
  477. AddEvent( e );
  478. e->SetChannel( this );
  479. e->SetActor( pActor );
  480. continue;
  481. }
  482. return false;
  483. }
  484. SetActive( buf.GetChar() == 1 ? true : false );
  485. return true;
  486. }