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.

200 lines
4.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include "movieobjects/timeutils.h"
  3. #include "tier0/dbg.h"
  4. #include "mathlib/mathlib.h"
  5. #include <math.h>
  6. ////////////////////////////////////////////////////////////////////////////////////////
  7. //
  8. // DmeFramerate_t
  9. //
  10. // exact (rational) representation of common framerates - any integral or ntsc framerate
  11. //
  12. ////////////////////////////////////////////////////////////////////////////////////////
  13. DmeFramerate_t::DmeFramerate_t( float fps )
  14. {
  15. SetFramerate( fps );
  16. }
  17. DmeFramerate_t::DmeFramerate_t( int fps /*= 0*/ ) :
  18. m_num( fps ), m_den( 10000 )
  19. {
  20. }
  21. DmeFramerate_t::DmeFramerate_t( int nNumerator, int nDenominator ) :
  22. m_num( nNumerator ), m_den( nDenominator * 10000 )
  23. {
  24. }
  25. void DmeFramerate_t::SetFramerate( float flFrameRate )
  26. {
  27. if ( IsIntegralValue( flFrameRate ) )
  28. {
  29. SetFramerate( RoundFloatToInt( flFrameRate ) );
  30. }
  31. else if ( IsIntegralValue( flFrameRate * 1001.0f / 1000.0f ) ) // 1001 is the ntsc divisor (30*1000/1001 = 29.97, etc)
  32. {
  33. SetFramerateNTSC( RoundFloatToInt( flFrameRate * 1001.0f / 1000.0f ) );
  34. }
  35. else
  36. {
  37. Assert( 0 );
  38. SetFramerate( RoundFloatToInt( flFrameRate ) );
  39. }
  40. }
  41. void DmeFramerate_t::SetFramerate( int fps )
  42. {
  43. m_num = fps;
  44. m_den = 10000;
  45. }
  46. // other (uncommon) options besides 30(29.97 - ntsc video) are 24 (23.976 - ntsc film) and 60 (59.94 - ntsc progressive)
  47. void DmeFramerate_t::SetFramerateNTSC( int multiplier /*= 30*/ )
  48. {
  49. // ntsc = 30 fps * 1000 / 1001
  50. // = ( 30 / 10000 fptms ) * 1000 / 1001
  51. // = 30 / 10010
  52. m_num = multiplier;
  53. m_den = 10010;
  54. }
  55. float DmeFramerate_t::GetFramesPerSecond() const
  56. {
  57. return 10000.0f * m_num / float( m_den );
  58. }
  59. ////////////////////////////////////////////////////////////////////////////////////////
  60. //
  61. // DmeTime_t
  62. //
  63. // representing time as integral tenths of a millisecond (tms)
  64. //
  65. ////////////////////////////////////////////////////////////////////////////////////////
  66. DmeTime_t::DmeTime_t( int frame, DmeFramerate_t framerate )
  67. {
  68. int64 num = int64( framerate.m_num );
  69. int64 prod = frame * int64( framerate.m_den );
  70. // add signed offset to force integer truncation (towards 0) to give us truncation towards -inf
  71. if ( frame < 0 )
  72. {
  73. prod -= num - 1;
  74. }
  75. m_tms = int( prod / num ); // round tms towards 0
  76. }
  77. // float operators - comment these out to find potentially incorrect uses of DmeTime_t
  78. DmeTime_t DmeTime_t::operator*=( float f )
  79. {
  80. m_tms = int( floor( m_tms * f + 0.5f ) );
  81. return *this;
  82. }
  83. DmeTime_t DmeTime_t::operator/=( float f )
  84. {
  85. m_tms = int( floor( m_tms / f + 0.5f ) );
  86. return *this;
  87. }
  88. // helper methods
  89. void DmeTime_t::Clamp( DmeTime_t lo, DmeTime_t hi )
  90. {
  91. m_tms = clamp( m_tms, lo.m_tms, hi.m_tms );
  92. }
  93. bool DmeTime_t::IsInRange( DmeTime_t lo, DmeTime_t hi ) const
  94. {
  95. return m_tms >= lo.m_tms && m_tms < hi.m_tms;
  96. }
  97. // helper functions
  98. float GetFractionOfTimeBetween( DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp /*= false*/ )
  99. {
  100. return GetFractionOfTime( t - start, end - start, bClamp );
  101. }
  102. float GetFractionOfTime( DmeTime_t t, DmeTime_t duration, bool bClamp /*= false*/ )
  103. {
  104. if ( duration == DMETIME_ZERO )
  105. return 0.0f;
  106. if ( bClamp )
  107. {
  108. t.Clamp( DMETIME_ZERO, duration );
  109. }
  110. return t.m_tms / float( duration.m_tms );
  111. }
  112. int FrameForTime( DmeTime_t t, DmeFramerate_t framerate )
  113. {
  114. return t.CurrentFrame( framerate );
  115. }
  116. // framerate-dependent conversions to/from frames
  117. int DmeTime_t::CurrentFrame( DmeFramerate_t framerate, bool bRoundDown ) const
  118. {
  119. int64 den = int64( framerate.m_den );
  120. int64 num = int64( framerate.m_num );
  121. int64 prod = int64( m_tms ) * num;
  122. // times within this range are considered on a frame: (frame*den/num - 1, frame*den/num]
  123. // this follows from the truncation towards -inf behavior of the frame,framerate constructor above
  124. // the following logic is there to ensure the above rule,
  125. // while working around the truncation towards 0 behavior of integer divide
  126. if ( m_tms < 0 )
  127. {
  128. if ( bRoundDown )
  129. prod -= den - num;
  130. }
  131. else
  132. {
  133. if ( bRoundDown )
  134. prod += num - 1;
  135. else
  136. prod += den - 1;
  137. }
  138. return int( prod / den );
  139. }
  140. DmeTime_t DmeTime_t::TimeAtCurrentFrame( DmeFramerate_t framerate, bool bRoundDown ) const
  141. {
  142. int frame = CurrentFrame( framerate, bRoundDown );
  143. return DmeTime_t( frame, framerate );
  144. }
  145. DmeTime_t DmeTime_t::TimeAtNextFrame( DmeFramerate_t framerate ) const
  146. {
  147. // since we always round towards -inf, go to next frame whether we're on a frame or not
  148. int frame = CurrentFrame( framerate, true );
  149. return DmeTime_t( frame + 1, framerate );
  150. }
  151. DmeTime_t DmeTime_t::TimeAtPrevFrame( DmeFramerate_t framerate ) const
  152. {
  153. int frame = CurrentFrame( framerate, false );
  154. return DmeTime_t( frame - 1, framerate ); // we're exactly on a frame
  155. }
  156. int DmeTime_t::RoundSecondsToTMS( float sec )
  157. {
  158. return floor( 10000.0f * sec + 0.5f ); // round at half-tms boundary
  159. }
  160. int DmeTime_t::RoundSecondsToTMS( double sec )
  161. {
  162. return floor( 10000.0 * sec + 0.5 ); // round at half-tms boundary
  163. }