Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

824 lines
21 KiB

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