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.

353 lines
8.1 KiB

  1. #include "cbase.h"
  2. #include <vgui/IVGui.h>
  3. #include <vgui/ISurface.h>
  4. #include "subtitlepanel.h"
  5. #include "filesystem.h"
  6. // memdbgon must be the last include file in a .cpp file!!!
  7. #include "tier0/memdbgon.h"
  8. using namespace vgui;
  9. #define MAX_CHEAP_LINES 10
  10. ConVar cheap_captions_test( "cheap_captions_test", "0", 0 );
  11. ConVar cheap_captions_fadetime( "cheap_captions_fadetime", "0.5", 0 );
  12. //-----------------------------------------------------------------------------
  13. // Purpose: Determines if we should be playing with captions
  14. //-----------------------------------------------------------------------------
  15. bool ShouldUseCaptioning()
  16. {
  17. if ( cheap_captions_test.GetBool() )
  18. {
  19. return true;
  20. }
  21. extern ConVar closecaption;
  22. return closecaption.GetBool();
  23. }
  24. CCaptionSequencer::CCaptionSequencer() :
  25. m_bCaptions( false )
  26. {
  27. Reset();
  28. }
  29. void CCaptionSequencer::Reset()
  30. {
  31. // captioning start when rendering stable, not simply at movie start
  32. m_CaptionStartTime = 0;
  33. m_flPauseTime = 0;
  34. m_flTotalPauseTime = 0;
  35. m_bPaused = false;
  36. // initial priming state to fetch a caption
  37. m_bShowingCaption = false;
  38. m_bCaptionStale = true;
  39. m_CurCaptionString[0] = '\0';
  40. m_CurCaptionStartTime = 0.0f;
  41. m_CurCaptionEndTime = 0.0f;
  42. m_CurCaptionColor = 0xFFFFFFFF;
  43. if ( m_CaptionBuf.TellPut() )
  44. {
  45. // reset to start
  46. m_CaptionBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  47. }
  48. else
  49. {
  50. m_CaptionBuf.Purge();
  51. }
  52. }
  53. bool CCaptionSequencer::Init( const char *pFilename )
  54. {
  55. Reset();
  56. m_bCaptions = false;
  57. if ( g_pFullFileSystem->ReadFile( pFilename, "GAME", m_CaptionBuf ) )
  58. {
  59. m_bCaptions = true;
  60. }
  61. return m_bCaptions;
  62. }
  63. void CCaptionSequencer::SetStartTime( float flStarTtime )
  64. {
  65. // Start our captions now
  66. m_CaptionStartTime = flStarTtime;
  67. }
  68. void CCaptionSequencer::Pause( bool bPause )
  69. {
  70. if ( m_bPaused == bPause )
  71. return;
  72. m_bPaused = bPause;
  73. if ( !m_bPaused )
  74. {
  75. // determine elapsed time paused
  76. m_flTotalPauseTime += Plat_FloatTime() - m_flPauseTime;
  77. }
  78. else
  79. {
  80. // stop the clock
  81. m_flPauseTime = Plat_FloatTime();
  82. }
  83. }
  84. float CCaptionSequencer::GetElapsedTime()
  85. {
  86. float flElapsed;
  87. if ( !m_bPaused )
  88. {
  89. flElapsed = Plat_FloatTime() - m_flTotalPauseTime - m_CaptionStartTime;
  90. }
  91. else
  92. {
  93. // hold the clock
  94. flElapsed = m_flPauseTime - m_flTotalPauseTime - m_CaptionStartTime;
  95. }
  96. return flElapsed;
  97. }
  98. bool CCaptionSequencer::GetCaptionToken( char *token, int tokenLen )
  99. {
  100. if ( !token || !tokenLen )
  101. return false;
  102. if ( !m_CaptionBuf.IsValid() )
  103. {
  104. // end of data
  105. return false;
  106. }
  107. m_CaptionBuf.GetLine( token, tokenLen );
  108. char *pCRLF = V_stristr( token, "\r" );
  109. if ( pCRLF )
  110. {
  111. *pCRLF = '\0';
  112. }
  113. m_CaptionBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 );
  114. return true;
  115. }
  116. bool CCaptionSequencer::GetNextCaption( void )
  117. {
  118. char buff[MAX_CAPTION_LENGTH];
  119. if ( !GetCaptionToken( m_CurCaptionString, sizeof( m_CurCaptionString ) ) )
  120. {
  121. // end of captions
  122. m_CurCaptionString[0] = '\0';
  123. return false;
  124. }
  125. // hex color
  126. GetCaptionToken( buff, sizeof( buff ) );
  127. sscanf( buff, "%x", &m_CurCaptionColor );
  128. // float start time
  129. GetCaptionToken( buff, sizeof( buff ) );
  130. m_CurCaptionStartTime = atof( buff );
  131. // float end time
  132. GetCaptionToken( buff, sizeof( buff ) );
  133. m_CurCaptionEndTime = atof( buff );
  134. // have valid caption
  135. m_bCaptionStale = false;
  136. return true;
  137. }
  138. const char *CCaptionSequencer::GetCurrentCaption( int *pColorOut )
  139. {
  140. if ( !m_bCaptions )
  141. {
  142. return NULL;
  143. }
  144. if ( m_CaptionStartTime )
  145. {
  146. // get a timeline
  147. float elapsed = GetElapsedTime();
  148. // Get a new caption because we've just finished one
  149. if ( !m_bShowingCaption && m_bCaptionStale )
  150. {
  151. GetNextCaption();
  152. }
  153. if ( m_bShowingCaption )
  154. {
  155. if ( elapsed > m_CurCaptionEndTime ) // Caption just turned off
  156. {
  157. m_bShowingCaption = false; // Don't draw caption
  158. m_bCaptionStale = true; // Trigger getting a new one on the next frame
  159. }
  160. }
  161. else
  162. {
  163. if ( elapsed > m_CurCaptionStartTime ) // Turn Caption on
  164. {
  165. m_bShowingCaption = true;
  166. }
  167. }
  168. if ( m_bShowingCaption && m_CurCaptionString[0] )
  169. {
  170. if ( pColorOut )
  171. {
  172. *pColorOut = m_CurCaptionColor;
  173. }
  174. return m_CurCaptionString;
  175. }
  176. }
  177. return NULL;
  178. }
  179. float CCaptionSequencer::GetAlpha()
  180. {
  181. if ( !m_bShowingCaption || m_bPaused )
  182. return 0;
  183. float flElapsed = GetElapsedTime();
  184. float flAlpha = RemapValClamped( flElapsed, m_CurCaptionStartTime, m_CurCaptionStartTime + cheap_captions_fadetime.GetFloat(), 0.0f, 255.0f );
  185. flAlpha = RemapValClamped( flElapsed, m_CurCaptionEndTime - cheap_captions_fadetime.GetFloat(), m_CurCaptionEndTime, flAlpha, 0.0f );
  186. return flAlpha;
  187. }
  188. CSubtitlePanel::CSubtitlePanel( vgui::Panel *pParent, const char *pCaptionFile, int nPlaybackHeight ) :
  189. vgui::Panel( pParent, "SubtitlePanel" )
  190. {
  191. SetScheme( "basemodui_scheme" );
  192. SetProportional( true );
  193. int nParentWide = pParent->GetWide();
  194. int nParentTall = pParent->GetTall();
  195. SetBounds( 0, 0, nParentWide, nParentTall );
  196. SetPaintBackgroundEnabled( true );
  197. m_hFont = vgui::INVALID_FONT;
  198. vgui::HScheme hScheme = vgui::scheme()->GetScheme( "basemodui_scheme" );
  199. vgui::IScheme *pNewScheme = vgui::scheme()->GetIScheme( hScheme );
  200. if ( pNewScheme )
  201. {
  202. m_hFont = pNewScheme->GetFont( IsGameConsole() ? "CloseCaption_Console" : "CloseCaption_Normal", true );
  203. }
  204. m_nFontTall = vgui::surface()->GetFontTall( m_hFont );
  205. m_pSubtitleLabel = new vgui::Label( this, "SubtitleLabel", L"" );
  206. m_pSubtitleLabel->SetFont( m_hFont );
  207. int nWidth = nParentWide * 0.60f;
  208. int xPos = ( nParentWide - nWidth ) / 2;
  209. // assume video is centered
  210. // must be scaled according to playback height, due to letterboxing
  211. // don't want to cut into or overlap border, need to be within video, and title safe
  212. // so pushes up according to font height
  213. int yOffset = ( nPlaybackHeight - nParentTall )/2;
  214. int yPos = ( 0.85f * nPlaybackHeight ) - yOffset;
  215. // captions are anchored to a baseline and grow upward
  216. // any resolution changes then are title safe
  217. // tall enough for 10 lines
  218. m_pSubtitleLabel->SetPos( xPos, yPos - m_nFontTall * MAX_CHEAP_LINES );
  219. m_pSubtitleLabel->SetTall( m_nFontTall * MAX_CHEAP_LINES );
  220. m_pSubtitleLabel->SetWide( nWidth );
  221. m_pSubtitleLabel->SetContentAlignment( vgui::Label::a_south );
  222. m_pSubtitleLabel->SetWrap( true );
  223. const char *pFixedCaptionFile = pCaptionFile;
  224. char captionFilename[MAX_PATH];
  225. if ( !V_stristr( pCaptionFile, ".txt" ) )
  226. {
  227. // Strip any possible extension, add on the '_captions.txt' ending
  228. V_StripExtension( pCaptionFile, captionFilename, MAX_PATH );
  229. V_strncat( captionFilename, "_captions.txt", MAX_PATH );
  230. pFixedCaptionFile = captionFilename;
  231. }
  232. // Setup our captions
  233. m_bHasCaptions = m_Captions.Init( pFixedCaptionFile );
  234. // prevent any thinking or drawing when captions absent
  235. SetVisible( m_bHasCaptions );
  236. }
  237. bool CSubtitlePanel::StartCaptions()
  238. {
  239. if ( !m_bHasCaptions )
  240. return false;
  241. m_Captions.SetStartTime( Plat_FloatTime() );
  242. return true;
  243. }
  244. void CSubtitlePanel::Pause( bool bPause )
  245. {
  246. m_Captions.Pause( bPause );
  247. }
  248. bool CSubtitlePanel::HasCaptions()
  249. {
  250. return m_bHasCaptions;
  251. }
  252. void CSubtitlePanel::OnThink()
  253. {
  254. int nColor = 0xFFFFFFFF;
  255. const char *pCaptionText = m_Captions.GetCurrentCaption( &nColor );
  256. m_pSubtitleLabel->SetText( pCaptionText );
  257. SetAlpha( ShouldUseCaptioning() ? m_Captions.GetAlpha() : 0 );
  258. if ( pCaptionText )
  259. {
  260. int r = ( nColor >> 24 ) & 0xFF;
  261. int g = ( nColor >> 16 ) & 0xFF;
  262. int b = ( nColor >> 8 ) & 0xFF;
  263. int a = ( nColor >> 0 ) & 0xFF;
  264. m_pSubtitleLabel->SetFgColor( Color( r, g, b, a ) );
  265. }
  266. }
  267. void CSubtitlePanel::PaintBackground()
  268. {
  269. int nMsgWide, nMsgTall;
  270. m_pSubtitleLabel->GetContentSize( nMsgWide, nMsgTall );
  271. if ( !nMsgWide || !nMsgTall )
  272. {
  273. return;
  274. }
  275. int nLabelX, nLabelY, nLabelWide, nLabelTall;
  276. m_pSubtitleLabel->GetBounds( nLabelX, nLabelY, nLabelWide, nLabelTall );
  277. // widen box to seat label better
  278. int nBoxWide = nLabelWide + GetWide() * 0.05f;
  279. int nBoxTall = nMsgTall + m_nFontTall;
  280. // center horizontally
  281. int nBoxX = ( GetWide() - nBoxWide )/2;
  282. // determine the top line of the south anchored text and center
  283. int nBoxY = ( nLabelY + nLabelTall ) - nMsgTall/2 - nBoxTall/2;
  284. DrawBox( nBoxX, nBoxY, nBoxWide, nBoxTall, Color( 0, 0, 0, 150 ), 1.0f );
  285. }