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.

818 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmetrack.h"
  7. #include "tier0/dbg.h"
  8. #include "datamodel/dmelementfactoryhelper.h"
  9. #include "movieobjects/dmeclip.h"
  10. #include "movieobjects/dmetrackgroup.h"
  11. #include "movieobjects_interfaces.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. //-----------------------------------------------------------------------------
  15. // The solo track
  16. //-----------------------------------------------------------------------------
  17. DmElementHandle_t CDmeTrack::m_hSoloTrack[ DMECLIP_TYPE_COUNT ] =
  18. {
  19. DMELEMENT_HANDLE_INVALID,
  20. DMELEMENT_HANDLE_INVALID,
  21. DMELEMENT_HANDLE_INVALID,
  22. DMELEMENT_HANDLE_INVALID,
  23. };
  24. //-----------------------------------------------------------------------------
  25. // CDmeTrack - common container class for clip objects
  26. //-----------------------------------------------------------------------------
  27. IMPLEMENT_ELEMENT_FACTORY( DmeTrack, CDmeTrack );
  28. void CDmeTrack::OnConstruction()
  29. {
  30. m_hOwner = DMELEMENT_HANDLE_INVALID;
  31. m_Flags.ClearAllFlags();
  32. m_Clips.Init( this, "children" );
  33. m_Collapsed.InitAndSet( this, "collapsed", true );
  34. m_Mute.InitAndSet( this, "mute", false );
  35. m_Synched.InitAndSet( this, "synched", true );
  36. m_ClipType.InitAndSet( this, "clipType", DMECLIP_UNKNOWN, FATTRIB_HAS_CALLBACK | FATTRIB_HAS_PRE_CALLBACK );
  37. m_Volume.InitAndSet( this, "volume", 1.0 );
  38. }
  39. void CDmeTrack::OnDestruction()
  40. {
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Methods of IDmElement
  44. //-----------------------------------------------------------------------------
  45. void CDmeTrack::OnAttributeChanged( CDmAttribute *pAttribute )
  46. {
  47. BaseClass::OnAttributeChanged( pAttribute );
  48. // Attach callbacks to detected sorted conditions if we're a film clip
  49. if ( pAttribute == m_ClipType.GetAttribute() )
  50. {
  51. if ( m_ClipType == DMECLIP_FILM )
  52. {
  53. m_Flags.ClearFlag( IS_SORTED );
  54. }
  55. return;
  56. }
  57. // This gets called when start/end time of children change, or if the array changes
  58. // This is a hack, since any OnAttributeChanged call that gets chained here from another element will trigger this
  59. // At some point, we'll probably have to start sending more data through OnAttributeChanged, (like an event string or chain path)
  60. // or perhaps add a new callback OnElementChanged() with this data
  61. if ( pAttribute == m_Clips.GetAttribute() || ( pAttribute->GetOwner() != this ) )
  62. {
  63. if ( !m_Flags.IsFlagSet( SUPPRESS_DIRTY_ORDERING ) )
  64. {
  65. m_Flags.ClearFlag( IS_SORTED );
  66. }
  67. return;
  68. }
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Clip type
  72. //-----------------------------------------------------------------------------
  73. DmeClipType_t CDmeTrack::GetClipType() const
  74. {
  75. return (DmeClipType_t)m_ClipType.Get();
  76. }
  77. void CDmeTrack::SetClipType( DmeClipType_t type )
  78. {
  79. m_ClipType = type;
  80. }
  81. void CDmeTrack::SetCollapsed( bool state )
  82. {
  83. m_Collapsed = state;
  84. }
  85. bool CDmeTrack::IsCollapsed() const
  86. {
  87. return m_Collapsed.Get();
  88. }
  89. void CDmeTrack::SetMute( bool state )
  90. {
  91. m_Mute = state;
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Volume
  95. //-----------------------------------------------------------------------------
  96. void CDmeTrack::SetVolume( float state )
  97. {
  98. m_Volume = state;
  99. }
  100. float CDmeTrack::GetVolume() const
  101. {
  102. return m_Volume.Get();
  103. }
  104. // Is this track synched to the film track?
  105. void CDmeTrack::SetSynched( bool bState )
  106. {
  107. m_Synched = bState;
  108. }
  109. bool CDmeTrack::IsSynched() const
  110. {
  111. return m_Synched;
  112. }
  113. bool CDmeTrack::IsMute( bool bCheckSoloing ) const
  114. {
  115. // if we're muted, don't play regardless of whether we're solo
  116. CDmeTrack *pSoloTrack = bCheckSoloing ? GetSoloTrack() : NULL;
  117. return m_Mute.Get() || ( pSoloTrack != this && pSoloTrack != NULL );
  118. }
  119. int CDmeTrack::GetClipCount() const
  120. {
  121. return m_Clips.Count();
  122. }
  123. CDmeClip *CDmeTrack::GetClip( int i ) const
  124. {
  125. return m_Clips[ i ];
  126. }
  127. const CUtlVector< DmElementHandle_t > &CDmeTrack::GetClips( ) const
  128. {
  129. return m_Clips.Get();
  130. }
  131. void CDmeTrack::AddClip( CDmeClip *clip )
  132. {
  133. if ( clip->GetClipType() == GetClipType() )
  134. {
  135. // FIXME: In the case of a non-overlapped track,
  136. // we could optimize this to insert the clip in sorted order,
  137. // then fix overlaps (fixing overlaps requires a sorted list)
  138. Assert( FindClip( clip ) < 0 );
  139. m_Clips.AddToTail( clip );
  140. }
  141. }
  142. void CDmeTrack::RemoveClip( int i )
  143. {
  144. // NOTE: Removal shouldn't cause sort order or fixup to become invalid
  145. CSuppressAutoFixup suppress( this, SUPPRESS_OVERLAP_FIXUP | SUPPRESS_DIRTY_ORDERING );
  146. m_Clips.Remove( i );
  147. }
  148. bool CDmeTrack::RemoveClip( CDmeClip *clip )
  149. {
  150. Assert( clip->GetClipType() == GetClipType() );
  151. int i = FindClip( clip );
  152. if ( i != -1 )
  153. {
  154. RemoveClip( i );
  155. return true;
  156. }
  157. return false;
  158. }
  159. void CDmeTrack::RemoveAllClips()
  160. {
  161. CSuppressAutoFixup suppress( this, SUPPRESS_OVERLAP_FIXUP | SUPPRESS_DIRTY_ORDERING );
  162. m_Clips.RemoveAll();
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Returns the solo track, if any
  166. //-----------------------------------------------------------------------------
  167. CDmeTrack *CDmeTrack::GetSoloTrack( DmeClipType_t clipType )
  168. {
  169. return GetElement< CDmeTrack >( m_hSoloTrack[ clipType ] );
  170. }
  171. void CDmeTrack::SetSoloTrack( DmeClipType_t clipType, CDmeTrack *pTrack )
  172. {
  173. m_hSoloTrack[ clipType ] = pTrack->GetHandle();
  174. }
  175. bool CDmeTrack::IsSoloTrack() const
  176. {
  177. return m_hSoloTrack[ GetClipType() ] == GetHandle();
  178. }
  179. CDmeTrack *CDmeTrack::GetSoloTrack() const
  180. {
  181. return GetSoloTrack( GetClipType() );
  182. }
  183. void CDmeTrack::SetSoloTrack( )
  184. {
  185. m_hSoloTrack[ GetClipType() ] = GetHandle();
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Methods related to finding clips
  189. //-----------------------------------------------------------------------------
  190. int CDmeTrack::FindClip( CDmeClip *clip )
  191. {
  192. Assert( clip->GetClipType() == GetClipType() );
  193. int c = m_Clips.Count();
  194. for ( int i = c - 1; i >= 0; --i )
  195. {
  196. if ( m_Clips[ i ] == clip )
  197. return i;
  198. }
  199. return -1;
  200. }
  201. CDmeClip *CDmeTrack::FindNamedClip( const char *name )
  202. {
  203. int c = m_Clips.Count();
  204. for ( int i = c - 1; i >= 0; --i )
  205. {
  206. CDmeClip *child = m_Clips[ i ];
  207. if ( child && !Q_stricmp( child->GetName(), name ) )
  208. return child;
  209. }
  210. return NULL;
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Find clips at, intersecting or within a particular time interval
  214. //-----------------------------------------------------------------------------
  215. void CDmeTrack::FindClipsAtTime( DmeTime_t time, DmeClipSkipFlag_t flags, CUtlVector< CDmeClip * >& clips ) const
  216. {
  217. if ( ( flags & DMESKIP_INVISIBLE ) && IsCollapsed() )
  218. return;
  219. if ( ( flags & DMESKIP_MUTED ) && IsMute() )
  220. return;
  221. int nClipCount = GetClipCount();
  222. for ( int j = 0; j < nClipCount; ++j )
  223. {
  224. CDmeClip *pSubClip = GetClip( j );
  225. if ( !pSubClip )
  226. continue;
  227. if ( ( flags & DMESKIP_MUTED ) && pSubClip->IsMute() )
  228. continue;
  229. if ( time.IsInRange( pSubClip->GetStartTime(), pSubClip->GetEndTime() ) )
  230. {
  231. clips.AddToTail( pSubClip );
  232. }
  233. }
  234. }
  235. void CDmeTrack::FindClipsIntersectingTime( DmeTime_t startTime, DmeTime_t endTime, DmeClipSkipFlag_t flags, CUtlVector< CDmeClip * >& clips ) const
  236. {
  237. if ( ( flags & DMESKIP_INVISIBLE ) && IsCollapsed() )
  238. return;
  239. if ( ( flags & DMESKIP_MUTED ) && IsMute() )
  240. return;
  241. int nClipCount = GetClipCount();
  242. for ( int j = 0; j < nClipCount; ++j )
  243. {
  244. CDmeClip *pSubClip = GetClip( j );
  245. if ( !pSubClip )
  246. continue;
  247. if ( ( flags & DMESKIP_MUTED ) && pSubClip->IsMute() )
  248. continue;
  249. DmeTime_t clipStart = pSubClip->GetStartTime();
  250. DmeTime_t clipEnd = pSubClip->GetEndTime();
  251. if ( clipEnd >= startTime && clipStart < endTime )
  252. {
  253. clips.AddToTail( pSubClip );
  254. }
  255. }
  256. }
  257. void CDmeTrack::FindClipsWithinTime( DmeTime_t startTime, DmeTime_t endTime, DmeClipSkipFlag_t flags, CUtlVector< CDmeClip * >& clips ) const
  258. {
  259. if ( ( flags & DMESKIP_INVISIBLE ) && IsCollapsed() )
  260. return;
  261. if ( ( flags & DMESKIP_MUTED ) && IsMute() )
  262. return;
  263. int nClipCount = GetClipCount();
  264. for ( int j = 0; j < nClipCount; ++j )
  265. {
  266. CDmeClip *pSubClip = GetClip( j );
  267. if ( !pSubClip )
  268. continue;
  269. if ( ( flags & DMESKIP_MUTED ) && pSubClip->IsMute() )
  270. continue;
  271. DmeTime_t clipStart = pSubClip->GetStartTime();
  272. DmeTime_t clipEnd = pSubClip->GetEndTime();
  273. if ( clipStart >= startTime && clipEnd <= endTime )
  274. {
  275. clips.AddToTail( pSubClip );
  276. }
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Methods related to shifting clips
  281. //-----------------------------------------------------------------------------
  282. void CDmeTrack::ShiftAllClips( DmeTime_t dt )
  283. {
  284. if ( dt == DmeTime_t( 0 ) )
  285. return;
  286. CSuppressAutoFixup suppress( this, SUPPRESS_OVERLAP_FIXUP | SUPPRESS_DIRTY_ORDERING );
  287. int c = GetClipCount();
  288. for ( int i = 0; i < c; ++i )
  289. {
  290. CDmeClip *pSubClip = m_Clips[ i ];
  291. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  292. }
  293. }
  294. void CDmeTrack::ShiftAllClipsAfter( DmeTime_t startTime, DmeTime_t dt, bool bTestStartingTime )
  295. {
  296. if ( dt == DmeTime_t( 0 ) )
  297. return;
  298. int c = GetClipCount();
  299. for ( int i = 0; i < c; ++i )
  300. {
  301. CDmeClip *pSubClip = GetClip( i );
  302. DmeTime_t testTime = bTestStartingTime ? pSubClip->GetStartTime() : pSubClip->GetEndTime();
  303. if ( startTime < testTime )
  304. {
  305. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  306. }
  307. }
  308. }
  309. void CDmeTrack::ShiftAllClipsBefore( DmeTime_t endTime, DmeTime_t dt, bool bTestEndingTime )
  310. {
  311. if ( dt == DmeTime_t( 0 ) )
  312. return;
  313. int c = GetClipCount();
  314. for ( int i = 0; i < c; ++i )
  315. {
  316. CDmeClip *pSubClip = GetClip( i );
  317. DmeTime_t testTime = bTestEndingTime ? pSubClip->GetEndTime() : pSubClip->GetStartTime();
  318. if ( endTime > testTime )
  319. {
  320. DmeTime_t startTime = pSubClip->GetStartTime();
  321. pSubClip->SetStartTime( startTime + dt );
  322. }
  323. }
  324. }
  325. //-----------------------------------------------------------------------------
  326. // A version that works only on film clips
  327. //-----------------------------------------------------------------------------
  328. void CDmeTrack::ShiftAllFilmClipsAfter( CDmeClip *pClip, DmeTime_t dt, bool bShiftClip )
  329. {
  330. Assert( IsFilmTrack() );
  331. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) || ( dt == DmeTime_t( 0 ) ) )
  332. return;
  333. // This algorithm requires sorted clips
  334. SortClipsByStartTime();
  335. int c = GetClipCount();
  336. for ( int i = c; --i >= 0; )
  337. {
  338. CDmeClip *pSubClip = GetClip( i );
  339. if ( pSubClip == pClip )
  340. {
  341. if ( bShiftClip )
  342. {
  343. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  344. }
  345. return;
  346. }
  347. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  348. }
  349. // Clip wasn't found!
  350. Assert( 0 );
  351. }
  352. void CDmeTrack::ShiftAllFilmClipsBefore( CDmeClip *pClip, DmeTime_t dt, bool bShiftClip )
  353. {
  354. Assert( IsFilmTrack() );
  355. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) || ( dt == DmeTime_t( 0 ) ) )
  356. return;
  357. // This algorithm requires sorted clips
  358. SortClipsByStartTime();
  359. int c = GetClipCount();
  360. for ( int i = 0; i < c; ++i )
  361. {
  362. CDmeClip *pSubClip = GetClip( i );
  363. if ( pSubClip == pClip )
  364. {
  365. if ( bShiftClip )
  366. {
  367. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  368. }
  369. return;
  370. }
  371. pSubClip->SetStartTime( pSubClip->GetStartTime() + dt );
  372. }
  373. // Clip wasn't found!
  374. Assert( 0 );
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Method to sort clips by start time
  378. //-----------------------------------------------------------------------------
  379. struct SortInfo_t
  380. {
  381. DmeTime_t m_startTime;
  382. CDmeClip *m_pClip;
  383. };
  384. static int ClipStartLessFunc( const void * lhs, const void * rhs )
  385. {
  386. SortInfo_t *pInfo1 = (SortInfo_t*)lhs;
  387. SortInfo_t *pInfo2 = (SortInfo_t*)rhs;
  388. if ( pInfo1->m_startTime == pInfo2->m_startTime )
  389. return 0;
  390. return pInfo1->m_startTime < pInfo2->m_startTime ? -1 : 1;
  391. }
  392. void CDmeTrack::SortClipsByStartTime( )
  393. {
  394. // If we're not a film clip, then we haven't installed callbacks to make sorting fast.
  395. // The IS_SORTED flag is some random state
  396. if ( (m_ClipType == DMECLIP_FILM) && m_Flags.IsFlagSet( IS_SORTED ) )
  397. return;
  398. m_Flags.SetFlag( IS_SORTED );
  399. int c = GetClipCount();
  400. if ( c <= 1 )
  401. return;
  402. DmeTime_t lastTime;
  403. SortInfo_t *pSortInfo = (SortInfo_t*)_alloca( c * sizeof(SortInfo_t) );
  404. for ( int i = 0; i < c; ++i )
  405. {
  406. CDmeClip *pSubClip = GetClip(i);
  407. pSortInfo[i].m_startTime = pSubClip ? pSubClip->GetStartTime() : DmeTime_t::InvalidTime();
  408. pSortInfo[i].m_pClip = pSubClip;
  409. if ( lastTime > pSortInfo[i].m_startTime )
  410. {
  411. m_Flags.ClearFlag( IS_SORTED );
  412. }
  413. lastTime = pSortInfo[i].m_startTime;
  414. }
  415. if ( m_Flags.IsFlagSet( IS_SORTED ) )
  416. return;
  417. m_Flags.SetFlag( IS_SORTED );
  418. qsort( pSortInfo, c, sizeof(SortInfo_t), ClipStartLessFunc );
  419. CSuppressAutoFixup suppress( this, SUPPRESS_OVERLAP_FIXUP | SUPPRESS_DIRTY_ORDERING );
  420. m_Clips.RemoveAll();
  421. for ( int i = 0; i < c; ++i )
  422. {
  423. m_Clips.AddToTail( pSortInfo[i].m_pClip );
  424. }
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Shifts all clips to be non-overlapping
  428. //-----------------------------------------------------------------------------
  429. void CDmeTrack::FixOverlaps()
  430. {
  431. int c = GetClipCount();
  432. if ( c <= 1 )
  433. return;
  434. SortClipsByStartTime();
  435. CSuppressAutoFixup suppress( this, SUPPRESS_OVERLAP_FIXUP | SUPPRESS_DIRTY_ORDERING );
  436. // Cull NULL clips
  437. int nActualCount = 0;
  438. CDmeClip **pClips = (CDmeClip**)_alloca( c * sizeof(CDmeClip*) );
  439. for ( int i = 0; i < c; ++i )
  440. {
  441. CDmeClip *pCurr = GetClip( i );
  442. if ( pCurr && ((i == 0) || (pClips[i-1] != pCurr)) )
  443. {
  444. pClips[nActualCount++] = pCurr;
  445. }
  446. }
  447. if ( nActualCount <= 1 )
  448. return;
  449. CDmeClip *pPrev = pClips[0];
  450. for ( int i = 1; i < nActualCount; ++i )
  451. {
  452. CDmeClip *pCurr = pClips[i];
  453. DmeTime_t prevEndTime = pPrev->GetEndTime();
  454. DmeTime_t startTime = pCurr->GetStartTime();
  455. if ( startTime < prevEndTime )
  456. {
  457. pCurr->SetStartTime( prevEndTime );
  458. }
  459. pPrev = pCurr;
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Finds a clip at a particular time
  464. //-----------------------------------------------------------------------------
  465. CDmeClip* CDmeTrack::FindFilmClipAtTime( DmeTime_t localTime )
  466. {
  467. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  468. return NULL;
  469. // This algorithm requires sorted clips
  470. SortClipsByStartTime();
  471. int c = GetClipCount();
  472. for ( int i = 0; i < c; ++i )
  473. {
  474. CDmeClip *pSubClip = GetClip( i );
  475. if ( pSubClip && pSubClip->GetStartTime() <= localTime && pSubClip->GetEndTime() > localTime )
  476. return pSubClip;
  477. }
  478. return NULL;
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Find first clip in a specific time range
  482. //-----------------------------------------------------------------------------
  483. CDmeClip* CDmeTrack::FindFirstFilmClipIntesectingTime( DmeTime_t localStartTime, DmeTime_t localEndTime )
  484. {
  485. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  486. return NULL;
  487. // This algorithm requires sorted clips
  488. SortClipsByStartTime();
  489. int c = GetClipCount();
  490. for ( int i = 0; i < c; ++i )
  491. {
  492. CDmeClip *pSubClip = GetClip( i );
  493. if ( !pSubClip )
  494. continue;
  495. if ( ( localStartTime < pSubClip->GetEndTime() ) && ( localEndTime >= pSubClip->GetStartTime() ) )
  496. return static_cast<CDmeFilmClip*>( pSubClip );
  497. if ( localEndTime <= pSubClip->GetStartTime() )
  498. break;
  499. }
  500. return NULL;
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Inserts space in a film track for a film clip
  504. //-----------------------------------------------------------------------------
  505. void CDmeTrack::InsertSpaceInFilmTrack( DmeTime_t localStartTime, DmeTime_t localEndTime )
  506. {
  507. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  508. return;
  509. // This algorithm requires sorted clips
  510. SortClipsByStartTime();
  511. CDmeClip *pClip = FindFirstFilmClipIntesectingTime( localStartTime, localEndTime );
  512. if ( pClip )
  513. {
  514. DmeTime_t filmStart = pClip->GetStartTime();
  515. DmeTime_t dt = localEndTime - filmStart;
  516. ShiftAllFilmClipsAfter( pClip, dt, true );
  517. }
  518. return;
  519. }
  520. //-----------------------------------------------------------------------------
  521. // Returns the next/previous clip in a film track
  522. //-----------------------------------------------------------------------------
  523. CDmeClip* CDmeTrack::FindPrevFilmClip( CDmeClip *pClip )
  524. {
  525. Assert( IsFilmTrack() );
  526. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  527. return NULL;
  528. // This algorithm requires sorted clips
  529. SortClipsByStartTime();
  530. if ( !pClip )
  531. return m_Clips[ m_Clips.Count() - 1 ];
  532. // FIXME: Could use a binary search here based on time.
  533. // Probably doesn't matter though, since there will usually not be a ton of tracks
  534. CDmeClip *pPrevClip = NULL;
  535. int c = GetClipCount();
  536. for ( int i = 0; i < c; ++i )
  537. {
  538. CDmeClip *pSubClip = GetClip( i );
  539. if ( pSubClip == pClip )
  540. return pPrevClip;
  541. pPrevClip = pSubClip;
  542. }
  543. return NULL;
  544. }
  545. CDmeClip* CDmeTrack::FindNextFilmClip( CDmeClip *pClip )
  546. {
  547. Assert( IsFilmTrack() );
  548. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  549. return NULL;
  550. // This algorithm requires sorted clips
  551. SortClipsByStartTime();
  552. if ( !pClip )
  553. return m_Clips[ 0 ];
  554. CDmeClip *pNextClip = NULL;
  555. int c = GetClipCount();
  556. for ( int i = c; --i >= 0; )
  557. {
  558. CDmeClip *pSubClip = GetClip( i );
  559. if ( pSubClip == pClip )
  560. return pNextClip;
  561. pNextClip = pSubClip;
  562. }
  563. return NULL;
  564. }
  565. void CDmeTrack::FindAdjacentFilmClips( CDmeClip *pClip, CDmeClip *&pPrevClip, CDmeClip *&pNextClip )
  566. {
  567. pPrevClip = pNextClip = NULL;
  568. Assert( IsFilmTrack() );
  569. if ( !IsFilmTrack() || !pClip || ( m_Clips.Count() == 0 ) )
  570. return;
  571. // This algorithm requires sorted clips
  572. SortClipsByStartTime();
  573. int c = GetClipCount();
  574. for ( int i = 0; i < c; ++i )
  575. {
  576. CDmeClip *pSubClip = GetClip( i );
  577. if ( pSubClip == pClip )
  578. {
  579. pNextClip = ( i != c-1 ) ? GetClip( i+1 ) : NULL;
  580. return;
  581. }
  582. pPrevClip = pSubClip;
  583. }
  584. pPrevClip = NULL;
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Gets the start/end time of the owning clip in local time
  588. //-----------------------------------------------------------------------------
  589. void CDmeTrack::FindAdjacentFilmClips( DmeTime_t localTime, CDmeClip *&pPrevClip, CDmeClip *&pNextClip )
  590. {
  591. pPrevClip = pNextClip = NULL;
  592. Assert( IsFilmTrack() );
  593. if ( !IsFilmTrack() || ( m_Clips.Count() == 0 ) )
  594. return;
  595. // This algorithm requires sorted clips
  596. SortClipsByStartTime();
  597. int c = GetClipCount();
  598. for ( int i = 0; i < c; ++i )
  599. {
  600. CDmeClip *pSubClip = GetClip( i );
  601. if ( localTime >= pSubClip->GetEndTime() )
  602. {
  603. pPrevClip = pSubClip;
  604. }
  605. if ( localTime < pSubClip->GetStartTime() )
  606. {
  607. pNextClip = pSubClip;
  608. break;
  609. }
  610. }
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Fills all gaps in a film track with slugs
  614. //-----------------------------------------------------------------------------
  615. void CDmeTrack::FillAllGapsWithSlugs( const char *pSlugName, DmeTime_t startTime, DmeTime_t endTime )
  616. {
  617. if ( !IsFilmTrack() )
  618. return;
  619. FixOverlaps();
  620. // Create temporary slugs to fill in the gaps
  621. bool bSlugAdded = false;
  622. int c = GetClipCount();
  623. for ( int i = 0; i < c; ++i )
  624. {
  625. CDmeClip *pFilmClip = GetClip(i);
  626. DmeTime_t clipStartTime = pFilmClip->GetStartTime();
  627. if ( clipStartTime > startTime )
  628. {
  629. // There's a gap, create a slug
  630. CDmeFilmClip *pSlug = CreateSlugClip( pSlugName, startTime, clipStartTime, GetFileId() );
  631. // This will add the slug to the end; so we don't have to
  632. // worry about iterating over it (we've cached off the initial count)
  633. AddClip( pSlug );
  634. bSlugAdded = true;
  635. }
  636. startTime = pFilmClip->GetEndTime();
  637. }
  638. if ( endTime > startTime )
  639. {
  640. // There's a gap, create a temporary slug
  641. CDmeFilmClip *pSlug = CreateSlugClip( pSlugName, startTime, endTime, GetFileId() );
  642. // This will add the slug to the end; so we don't have to
  643. // worry about iterating over it (we've cached off the initial count)
  644. AddClip( pSlug );
  645. bSlugAdded = true;
  646. }
  647. if ( bSlugAdded )
  648. {
  649. FixOverlaps();
  650. }
  651. }
  652. //-----------------------------------------------------------------------------
  653. // helper methods
  654. //-----------------------------------------------------------------------------
  655. CDmeTrackGroup *GetParentTrackGroup( CDmeTrack *pTrack )
  656. {
  657. DmAttributeReferenceIterator_t hAttr = g_pDataModel->FirstAttributeReferencingElement( pTrack->GetHandle() );
  658. for ( ; hAttr != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; hAttr = g_pDataModel->NextAttributeReferencingElement( hAttr ) )
  659. {
  660. CDmAttribute *pAttr = g_pDataModel->GetAttribute( hAttr );
  661. if ( !pAttr )
  662. continue;
  663. CDmeTrackGroup *pTrackGroup = CastElement< CDmeTrackGroup >( pAttr->GetOwner() );
  664. if ( pTrackGroup )
  665. return pTrackGroup;
  666. }
  667. return NULL;
  668. }