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.

1066 lines
30 KiB

  1. //====== Copyright � 1996-2007, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: VGUI panel which can play back video, in-engine
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include <vgui/IVGui.h>
  8. #include "vgui/IInput.h"
  9. #include <vgui/ISurface.h>
  10. #include "ienginevgui.h"
  11. #include "iclientmode.h"
  12. #include "vgui_video.h"
  13. #include "engine/IEngineSound.h"
  14. #include "vgui/ILocalize.h"
  15. #if defined(PORTAL2)
  16. #include "portal2/basemodui.h"
  17. #endif
  18. #include "subtitlepanel.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. using namespace vgui;
  22. #ifdef PORTAL2
  23. using namespace BaseModUI;
  24. #endif
  25. ConVar bink_preload_videopanel_movies( "bink_preload_videopanel_movies", "1", 0, "Preload Bink movies used by VideoPanel." );
  26. static CUtlVector< VideoPanel * > g_vecVideoPanels;
  27. enum VideoAllowInterrupt_t
  28. {
  29. VIDEO_NO_INTERRUPT = 0,
  30. VIDEO_ALLOW_INTERRUPT = 1,
  31. VIDEO_ALLOW_INTERRUPT_DEV_ONLY,
  32. };
  33. // This is a hack due to the fact that the user can type quit with the video panel up, but it's parented to the GameUI dll root panel, which is already gone so
  34. // we would crash in the destructor.
  35. void VGui_ClearVideoPanels()
  36. {
  37. for ( int i = g_vecVideoPanels.Count() - 1; i >= 0; --i )
  38. {
  39. if ( g_vecVideoPanels[ i ] )
  40. {
  41. delete g_vecVideoPanels[ i ];
  42. }
  43. }
  44. g_vecVideoPanels.RemoveAll();
  45. }
  46. void VGui_ClearTransitionVideoPanels()
  47. {
  48. for ( int i = g_vecVideoPanels.Count() - 1; i >= 0; --i )
  49. {
  50. if ( g_vecVideoPanels[ i ] && g_vecVideoPanels[ i ]->IsTransitionVideo() )
  51. {
  52. g_vecVideoPanels[ i ]->StopPlayback();
  53. }
  54. }
  55. }
  56. void VGui_StopAllVideoPanels()
  57. {
  58. for ( int i = g_vecVideoPanels.Count() - 1; i >= 0; --i )
  59. {
  60. if ( g_vecVideoPanels[ i ] )
  61. {
  62. // instant termination required
  63. // no exit commands are allowed to run
  64. // no deferring shutdown or fade out possible
  65. g_vecVideoPanels[ i ]->StopPlayback( true );
  66. }
  67. }
  68. }
  69. bool VGui_IsPlayingFullScreenVideo()
  70. {
  71. if ( !enginevgui )
  72. {
  73. // not sure this interface is available when we get called
  74. return false;
  75. }
  76. #ifdef PORTAL2
  77. vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEDLL );
  78. #else
  79. vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEUIDLL );
  80. #endif
  81. for ( int i = g_vecVideoPanels.Count() - 1; i >= 0; --i )
  82. {
  83. VideoPanel *pVideoPanel = g_vecVideoPanels[i];
  84. if ( !pVideoPanel )
  85. continue;
  86. if ( pVideoPanel->GetVParent() != pParent )
  87. continue;
  88. if ( pVideoPanel->IsVisible() && pVideoPanel->IsEnabled() && pVideoPanel->IsPlaying() )
  89. {
  90. int wide;
  91. int tall;
  92. pVideoPanel->GetSize( wide, tall );
  93. int screenWide;
  94. int screenTall;
  95. vgui::surface()->GetScreenSize( screenWide, screenTall );
  96. if ( wide == screenWide && tall == screenTall )
  97. {
  98. return true;
  99. }
  100. }
  101. }
  102. return false;
  103. }
  104. VideoPanel::VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHeight, unsigned int nWidth ) :
  105. BaseClass( NULL, "VideoPanel" ),
  106. m_BIKHandle( BIKHANDLE_INVALID ),
  107. m_nPlaybackWidth( 0 ),
  108. m_nPlaybackHeight( 0 ),
  109. m_nShutdownCount( 0 ),
  110. m_bLooping( false ),
  111. m_bStopAllSounds( true ),
  112. m_nAllowInterruption( VIDEO_NO_INTERRUPT ),
  113. m_bStarted( false ),
  114. m_bIsTransitionVideo( false ),
  115. m_bShouldPreload( false ),
  116. m_bEnablePartnerUI( false )
  117. {
  118. m_flStartPlayTime = 0;
  119. m_flFadeInTime = 0;
  120. m_flFadeInEndTime = 0;
  121. m_flFadeOutTime = 0;
  122. m_flFadeOutEndTime = 0;
  123. m_flCurrentVolume = 0;
  124. m_bBlackBackground = true;
  125. m_pWaitingForPlayers = NULL;
  126. m_pPnlGamerPic = NULL;
  127. m_pLblGamerTag = NULL;
  128. m_pLblGamerTagStatus = NULL;
  129. m_pSubtitlePanel = NULL;
  130. #ifdef PORTAL2
  131. vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEDLL );
  132. #else
  133. vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEUIDLL );
  134. #endif // PORTAL2
  135. SetParent( pParent );
  136. SetVisible( false );
  137. SetKeyBoardInputEnabled( true );
  138. SetMouseInputEnabled( true );
  139. SetVisible( true );
  140. SetPaintBackgroundEnabled( false );
  141. SetPaintBorderEnabled( false );
  142. SetPostChildPaintEnabled( true );
  143. // Set us up
  144. SetTall( nHeight );
  145. SetWide( nWidth );
  146. SetPos( nXPos, nYPos );
  147. SetScheme( "basemodui_scheme" );
  148. SetProportional( true );
  149. // Let us update
  150. vgui::ivgui()->AddTickSignal( GetVPanel() );
  151. g_vecVideoPanels.AddToTail( this );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Properly shutdown out materials
  155. //-----------------------------------------------------------------------------
  156. VideoPanel::~VideoPanel( void )
  157. {
  158. delete m_pSubtitlePanel;
  159. g_vecVideoPanels.FindAndRemove( this );
  160. #if !defined( _GAMECONSOLE ) || defined( BINK_ENABLED_FOR_CONSOLE )
  161. // Shut down this video
  162. if ( m_BIKHandle != BIKHANDLE_INVALID )
  163. {
  164. bik->DestroyMaterial( m_BIKHandle );
  165. m_BIKHandle = BIKHANDLE_INVALID;
  166. m_pMaterial = NULL;
  167. }
  168. #endif
  169. }
  170. void VideoPanel::LoadLayout()
  171. {
  172. LoadControlSettings( "resource/UI/VideoPanel.res" );
  173. MakeReadyForUse();
  174. }
  175. void VideoPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  176. {
  177. BaseClass::ApplySchemeSettings( pScheme );
  178. LoadLayout();
  179. // partner overlay ui presentation
  180. m_pWaitingForPlayers = dynamic_cast< vgui::Label* >( FindChildByName( "WaitingForPlayers" ) );
  181. m_pPnlGamerPic = dynamic_cast< vgui::ImagePanel* >( FindChildByName( "PnlGamerPic" ) );
  182. m_pLblGamerTag = dynamic_cast< vgui::Label* >( FindChildByName( "LblGamerTag" ) );
  183. m_pLblGamerTagStatus = dynamic_cast< vgui::Label* >( FindChildByName( "LblGamerTagStatus" ) );
  184. #ifdef PORTAL2
  185. SetupPartnerInScience( m_bEnablePartnerUI );
  186. #endif
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose: Keeps a tab on when the movie is ending and allows a frame to pass to prevent threading issues
  190. //-----------------------------------------------------------------------------
  191. void VideoPanel::OnTick( void )
  192. {
  193. if ( m_nShutdownCount > 0 )
  194. {
  195. m_nShutdownCount++;
  196. if ( m_nShutdownCount > 10 )
  197. {
  198. OnClose();
  199. m_nShutdownCount = 0;
  200. }
  201. }
  202. else
  203. {
  204. ConVarRef volumeConVar( "volume" );
  205. float flMasterVolume = volumeConVar.IsValid() ? volumeConVar.GetFloat() : 0;
  206. if ( m_flCurrentVolume != flMasterVolume )
  207. {
  208. // for safety, only update on real change
  209. m_flCurrentVolume = flMasterVolume;
  210. bik->UpdateVolume( m_BIKHandle );
  211. }
  212. }
  213. bool bPartnerUIVisible = m_bEnablePartnerUI;
  214. if ( engine->IsPaused() || enginevgui->IsGameUIVisible() )
  215. {
  216. bPartnerUIVisible = false;
  217. }
  218. #ifdef PORTAL2
  219. if ( m_pWaitingForPlayers && m_pWaitingForPlayers->IsVisible() != bPartnerUIVisible )
  220. {
  221. SetupPartnerInScience( bPartnerUIVisible );
  222. }
  223. #endif
  224. BaseClass::OnTick();
  225. }
  226. void VideoPanel::OnVideoOver()
  227. {
  228. StopPlayback();
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose: Begins playback of a movie
  232. // Output : Returns true on success, false on failure.
  233. //-----------------------------------------------------------------------------
  234. bool VideoPanel::BeginPlayback( const char *pFilename )
  235. {
  236. if ( !pFilename || pFilename[ 0 ] == '\0' )
  237. return false;
  238. #if !defined( _GAMECONSOLE ) || defined( BINK_ENABLED_FOR_CONSOLE )
  239. // Destroy any previously allocated video
  240. if ( m_BIKHandle != BIKHANDLE_INVALID )
  241. {
  242. bik->DestroyMaterial( m_BIKHandle );
  243. m_BIKHandle = BIKHANDLE_INVALID;
  244. m_pMaterial = NULL;
  245. }
  246. // Load and create our BINK video
  247. int nFlags = ( m_bLooping ? BIK_LOOP : 0 );
  248. // only preload the transition videos
  249. // in-game videos are precached with aan alternate system
  250. if ( ( bink_preload_videopanel_movies.GetBool() && m_bIsTransitionVideo ) || m_bShouldPreload )
  251. {
  252. nFlags |= BIK_PRELOAD;
  253. }
  254. char szMaterialName[ FILENAME_MAX ];
  255. Q_snprintf( szMaterialName, sizeof( szMaterialName ), "VideoBIKMaterial%i", g_pBIK->GetGlobalMaterialAllocationNumber() );
  256. m_BIKHandle = bik->CreateMaterial( szMaterialName, pFilename, "GAME", nFlags );
  257. if ( m_BIKHandle == BIKHANDLE_INVALID )
  258. {
  259. return false;
  260. }
  261. m_bStarted = true;
  262. m_flCurrentVolume = 0;
  263. // We want to be the sole audio source
  264. if ( m_bStopAllSounds )
  265. {
  266. enginesound->NotifyBeginMoviePlayback();
  267. }
  268. int nWidth, nHeight;
  269. bik->GetFrameSize( m_BIKHandle, &nWidth, &nHeight );
  270. bik->GetTexCoordRange( m_BIKHandle, &m_flU, &m_flV );
  271. m_pMaterial = bik->GetMaterial( m_BIKHandle );
  272. DevMsg( "Bink video \"%s\" size: %d %d\n", pFilename, nWidth, nHeight );
  273. const AspectRatioInfo_t &aspectRatioInfo = materials->GetAspectRatioInfo();
  274. float flPhysicalFrameRatio = aspectRatioInfo.m_flFrameBuffertoPhysicalScalar * ( ( float )GetWide() / ( float )GetTall() );
  275. float flVideoRatio = ( ( float )nWidth / ( float )nHeight );
  276. // m_nPlaybackWidth and m_nPlaybackHeight are the dimensions of a panel that contains the entire bink movie in device pixels.
  277. // This code-path assumes that we want to letterbox.
  278. if ( flVideoRatio > flPhysicalFrameRatio )
  279. {
  280. m_nPlaybackWidth = GetWide();
  281. // Have to account for the difference between physical and pixel aspect ratios.
  282. m_nPlaybackHeight = ( ( float )GetWide() / aspectRatioInfo.m_flPhysicalToFrameBufferScalar ) / flVideoRatio;
  283. }
  284. else if ( flVideoRatio < flPhysicalFrameRatio )
  285. {
  286. // Have to account for the difference between physical and pixel aspect ratios.
  287. m_nPlaybackWidth = ( float )GetTall() * flVideoRatio * aspectRatioInfo.m_flPhysicalToFrameBufferScalar;
  288. m_nPlaybackHeight = GetTall();
  289. }
  290. else
  291. {
  292. m_nPlaybackWidth = GetWide();
  293. m_nPlaybackHeight = GetTall();
  294. }
  295. SetupCaptioning( pFilename, m_nPlaybackHeight );
  296. m_flStartPlayTime = gpGlobals->realtime;
  297. return true;
  298. #else
  299. return false;
  300. #endif
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Purpose:
  304. //-----------------------------------------------------------------------------
  305. void VideoPanel::Activate( void )
  306. {
  307. SetVisible( true );
  308. SetEnabled( true );
  309. vgui::surface()->SetMinimized( GetVPanel(), false );
  310. // Set the correct order
  311. vgui::VPANEL vpanelGameUI = enginevgui->GetPanel( PANEL_GAMEUIBACKGROUND );
  312. vgui::VPANEL vpanelThis = GetVPanel();
  313. vgui::ipanel()->SetZPos( vpanelThis, vgui::ipanel()->GetZPos( vpanelGameUI ) - 1 ); // place it just under gameui
  314. static ConVarRef cv_vguipanel_active( "vgui_panel_active" );
  315. cv_vguipanel_active.SetValue( cv_vguipanel_active.GetInt() + 1 );
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. //-----------------------------------------------------------------------------
  320. void VideoPanel::DoModal( void )
  321. {
  322. Activate();
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. void VideoPanel::OnKeyCodeTyped( vgui::KeyCode code )
  328. {
  329. static ConVarRef con_enable("con_enable");
  330. bool bConsoleEnabled = (con_enable.IsValid() && con_enable.GetBool()) ? true : false;
  331. bool bAllowDevInterrupt = (bConsoleEnabled && m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT_DEV_ONLY);
  332. bool bInterruptKeyPressed = ( code == KEY_ESCAPE );
  333. if ( (m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT || bAllowDevInterrupt) && bInterruptKeyPressed )
  334. {
  335. StopPlayback();
  336. }
  337. else
  338. {
  339. BaseClass::OnKeyCodeTyped( code );
  340. }
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose: Handle keys that should cause us to close
  344. //-----------------------------------------------------------------------------
  345. void VideoPanel::OnKeyCodePressed( vgui::KeyCode keycode )
  346. {
  347. vgui::KeyCode code = GetBaseButtonCode( keycode );
  348. bool bDevInteruptKeyPressed = ( code == KEY_ESCAPE || code == KEY_BACKQUOTE );
  349. // All these keys will interrupt playback
  350. bool bInterruptKeyPressed = ( bDevInteruptKeyPressed ||
  351. code == KEY_SPACE ||
  352. code == KEY_ENTER ||
  353. code == KEY_XBUTTON_A ||
  354. code == KEY_XBUTTON_B ||
  355. code == KEY_XBUTTON_X ||
  356. code == KEY_XBUTTON_Y ||
  357. code == KEY_XBUTTON_START ||
  358. code == KEY_XBUTTON_BACK );
  359. static ConVarRef con_enable("con_enable");
  360. bool bConsoleEnabled = (con_enable.IsValid() && con_enable.GetBool()) ? true : false;
  361. bool bAllowDevInterrupt = (bConsoleEnabled && m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT_DEV_ONLY);
  362. // These keys cause the panel to shutdown
  363. if ( ( m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT && bInterruptKeyPressed ) || ( bAllowDevInterrupt && bDevInteruptKeyPressed ) )
  364. {
  365. StopPlayback();
  366. }
  367. else
  368. {
  369. BaseClass::OnKeyCodePressed( keycode );
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: Handle mouse input that should cause us to close
  374. //-----------------------------------------------------------------------------
  375. void VideoPanel::OnMousePressed( vgui::MouseCode code )
  376. {
  377. static ConVarRef con_enable("con_enable");
  378. bool bConsoleEnabled = (con_enable.IsValid() && con_enable.GetBool()) ? true : false;
  379. bool bAllowDevInterrupt = (bConsoleEnabled && m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT_DEV_ONLY);
  380. if ( (m_nAllowInterruption == VIDEO_ALLOW_INTERRUPT || bAllowDevInterrupt) )
  381. {
  382. StopPlayback();
  383. }
  384. else
  385. {
  386. BaseClass::OnMousePressed( code );
  387. }
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose:
  391. //-----------------------------------------------------------------------------
  392. void VideoPanel::StopPlayback( bool bTerminate )
  393. {
  394. SetVisible( false );
  395. if ( !bTerminate )
  396. {
  397. // Start the deferred shutdown process
  398. m_nShutdownCount = 1;
  399. }
  400. else
  401. {
  402. // caller wants instant termination
  403. // prevent any exit command
  404. m_nShutdownCount = 0;
  405. m_ExitCommand.Clear();
  406. OnClose();
  407. // Destroy any previously allocated video
  408. if ( m_BIKHandle != BIKHANDLE_INVALID )
  409. {
  410. bik->DestroyMaterial( m_BIKHandle );
  411. m_BIKHandle = BIKHANDLE_INVALID;
  412. m_pMaterial = NULL;
  413. }
  414. }
  415. }
  416. void VideoPanel::SetFadeInTime( float flTime )
  417. {
  418. m_flFadeInTime = flTime;
  419. m_flFadeInEndTime = gpGlobals->realtime + flTime;
  420. SetAlpha( 0 );
  421. }
  422. void VideoPanel::SetFadeOutTime( float flTime )
  423. {
  424. m_flFadeOutTime = flTime;
  425. m_flFadeOutEndTime = gpGlobals->realtime + flTime;
  426. }
  427. #if defined( PORTAL2 )
  428. void VideoPanel::EnablePartnerUI( bool bEnablePartnerUI )
  429. {
  430. m_bEnablePartnerUI = false;
  431. if ( bEnablePartnerUI )
  432. {
  433. if ( GameRules() && GameRules()->IsMultiplayer() && ( XBX_GetNumGameUsers() == 1 ) )
  434. {
  435. IMatchSession *pSession = g_pMatchFramework->GetMatchSession();
  436. if ( pSession )
  437. {
  438. const char *pNetworkString = pSession->GetSessionSettings()->GetString( "system/network" );
  439. if ( !V_stricmp( pNetworkString, "lan" ) || !V_stricmp( pNetworkString, "live" ) )
  440. {
  441. // only allowing the partner ui for lan/live coop games
  442. m_bEnablePartnerUI = true;
  443. }
  444. }
  445. }
  446. }
  447. }
  448. #endif
  449. //-----------------------------------------------------------------------------
  450. // Purpose:
  451. //-----------------------------------------------------------------------------
  452. void VideoPanel::OnClose()
  453. {
  454. DevMsg( "VideoPanel::OnClose() played video for %.2f seconds\n", gpGlobals->realtime - m_flStartPlayTime );
  455. if ( m_bStopAllSounds )
  456. {
  457. enginesound->NotifyEndMoviePlayback();
  458. }
  459. BaseClass::OnClose();
  460. if ( vgui::input()->GetAppModalSurface() == GetVPanel() )
  461. {
  462. vgui::input()->ReleaseAppModalSurface();
  463. }
  464. // Fire an exit command if we're asked to do so
  465. if ( !m_ExitCommand.IsEmpty() )
  466. {
  467. engine->ClientCmd( m_ExitCommand.Get() );
  468. }
  469. MarkForDeletion();
  470. static ConVarRef cv_vguipanel_active( "vgui_panel_active" );
  471. cv_vguipanel_active.SetValue( cv_vguipanel_active.GetInt() - 1 );
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose:
  475. //-----------------------------------------------------------------------------
  476. void VideoPanel::GetPanelPos( int &xpos, int &ypos )
  477. {
  478. xpos = ( (float) ( GetWide() - m_nPlaybackWidth ) / 2 );
  479. ypos = ( (float) ( GetTall() - m_nPlaybackHeight ) / 2 );
  480. }
  481. //-----------------------------------------------------------------------------
  482. // Purpose: Update and draw the frame
  483. //-----------------------------------------------------------------------------
  484. float VideoPanel::DrawMovieFrame( void )
  485. {
  486. // No video to play, so do nothing
  487. if ( m_BIKHandle == BIKHANDLE_INVALID || m_pMaterial == NULL )
  488. return 0;
  489. #if !defined( _GAMECONSOLE ) || defined( BINK_ENABLED_FOR_CONSOLE )
  490. // Update our frame, but only if Bink is ready for us to process another frame.
  491. // We aren't really swapping here, but ReadyForSwap is a good way to throttle.
  492. // We'd rather throttle this way so that we don't limit the overall frame rate of the system.
  493. // TODO: is this valid with threaded bink changes?
  494. // if ( g_pBIK->ReadyForSwap( m_BIKHandle ) )
  495. {
  496. if ( g_pBIK->Update( m_BIKHandle ) == false )
  497. {
  498. // Issue a close command
  499. OnVideoOver();
  500. OnClose();
  501. }
  502. }
  503. #else
  504. return 0;
  505. #endif
  506. // Sit in the "center"
  507. int xpos, ypos;
  508. GetPanelPos( xpos, ypos );
  509. LocalToScreen( xpos, ypos );
  510. float alpha = ((float)GetFgColor()[3]/255.0f);
  511. float frac = 1.0f;
  512. if ( m_flFadeOutTime > 0 )
  513. {
  514. m_flFadeInTime = 0;
  515. frac = ( m_flFadeOutEndTime - gpGlobals->realtime ) / m_flFadeOutTime;
  516. }
  517. else if ( m_flFadeInTime > 0 )
  518. {
  519. m_flFadeOutTime = 0;
  520. frac = 1.0f - (( m_flFadeInEndTime - gpGlobals->realtime ) / m_flFadeInTime);
  521. }
  522. //alpha = frac * 255;
  523. alpha = clamp( frac, 0.0f, 1.0f );
  524. // if this is a level transition movie and something happened in between transition, we don't want users to be stuck here
  525. // so we just kill the movie after 60 seconds to be sure, this may be too short, we'll have to see
  526. bool bForceTimeout = !engine->IsConnected() && IsTransitionVideo();
  527. if ( bForceTimeout || (alpha <= 0 && m_flFadeOutTime > 0) )
  528. {
  529. m_flFadeOutTime = 0;
  530. // Issue a close command
  531. StopPlayback();
  532. return alpha;
  533. }
  534. else if ( m_flFadeInEndTime < gpGlobals->realtime )
  535. {
  536. m_flFadeInTime = 0;
  537. }
  538. // Black out the background (we could omit drawing under the video surface, but this is straight-forward)
  539. if ( m_bBlackBackground )
  540. {
  541. vgui::surface()->DrawSetColor( 0, 0, 0, (alpha*255) );
  542. vgui::surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
  543. }
  544. // Draw the polys to draw this out
  545. CMatRenderContextPtr pRenderContext( materials );
  546. pRenderContext->MatrixMode( MATERIAL_VIEW );
  547. pRenderContext->PushMatrix();
  548. pRenderContext->LoadIdentity();
  549. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  550. pRenderContext->PushMatrix();
  551. pRenderContext->LoadIdentity();
  552. pRenderContext->Bind( m_pMaterial, NULL );
  553. CMeshBuilder meshBuilder;
  554. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  555. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  556. float flLeftX = xpos;
  557. float flRightX = xpos + (m_nPlaybackWidth-1);
  558. float flTopY = ypos;
  559. float flBottomY = ypos + (m_nPlaybackHeight-1);
  560. // Map our UVs to cut out just the portion of the video we're interested in
  561. float flLeftU = 0.0f;
  562. float flTopV = 0.0f;
  563. // We need to subtract off a pixel to make sure we don't bleed
  564. float flRightU = m_flU - ( 1.0f / (float) m_nPlaybackWidth );
  565. float flBottomV = m_flV - ( 1.0f / (float) m_nPlaybackHeight );
  566. // Get the current viewport size
  567. int vx, vy, vw, vh;
  568. pRenderContext->GetViewport( vx, vy, vw, vh );
  569. // map from screen pixel coords to -1..1
  570. flRightX = FLerp( -1, 1, 0, vw, flRightX );
  571. flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
  572. flTopY = FLerp( 1, -1, 0, vh ,flTopY );
  573. flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
  574. for ( int corner=0; corner<4; corner++ )
  575. {
  576. bool bLeft = (corner==0) || (corner==3);
  577. meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f );
  578. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  579. meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
  580. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  581. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  582. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, alpha );
  583. meshBuilder.AdvanceVertex();
  584. }
  585. meshBuilder.End();
  586. pMesh->Draw();
  587. pRenderContext->MatrixMode( MATERIAL_VIEW );
  588. pRenderContext->PopMatrix();
  589. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  590. pRenderContext->PopMatrix();
  591. return alpha;
  592. }
  593. void VideoPanel::Paint()
  594. {
  595. BaseClass::Paint();
  596. #ifdef PORTAL2
  597. float flAlpha = DrawMovieFrame();
  598. if ( m_bEnablePartnerUI )
  599. {
  600. SetPartnerInScienceAlpha( flAlpha * 255.0f );
  601. }
  602. #else
  603. DrawMovieFrame();
  604. #endif
  605. }
  606. void VideoPanel::PostChildPaint()
  607. {
  608. if ( engine->IsPaused() || (enginevgui->IsGameUIVisible()
  609. #ifdef PORTAL2
  610. && !CBaseModPanel::GetSingleton().IsLevelLoading()
  611. #endif
  612. ) )
  613. {
  614. vgui::surface()->DrawSetColor( 0, 0, 0, 150 );
  615. vgui::surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
  616. }
  617. }
  618. bool VideoPanel::IsPlaying()
  619. {
  620. if ( m_BIKHandle == BIKHANDLE_INVALID || m_pMaterial == NULL )
  621. return false;
  622. return true;
  623. }
  624. #if defined( PORTAL2 )
  625. void VideoPanel::SetupPartnerInScience( bool bEnable )
  626. {
  627. if ( bEnable )
  628. {
  629. CBaseModPanel::GetSingleton().SetupPartnerInScience();
  630. }
  631. if ( m_pWaitingForPlayers )
  632. {
  633. m_pWaitingForPlayers->SetVisible( bEnable );
  634. }
  635. if ( m_pPnlGamerPic )
  636. {
  637. if ( bEnable )
  638. {
  639. vgui::IImage *pAvatarImage = CBaseModPanel::GetSingleton().GetPartnerImage();
  640. if ( pAvatarImage )
  641. {
  642. m_pPnlGamerPic->SetImage( pAvatarImage );
  643. }
  644. else
  645. {
  646. m_pPnlGamerPic->SetImage( "icon_lobby" );
  647. }
  648. }
  649. m_pPnlGamerPic->SetVisible( bEnable );
  650. }
  651. if ( m_pLblGamerTag )
  652. {
  653. if ( bEnable )
  654. {
  655. CUtlString partnerName = CBaseModPanel::GetSingleton().GetPartnerName();
  656. m_pLblGamerTag->SetText( partnerName.Get() );
  657. }
  658. m_pLblGamerTag->SetVisible( bEnable );
  659. }
  660. if ( m_pLblGamerTagStatus )
  661. {
  662. m_pLblGamerTagStatus->SetVisible( bEnable );
  663. m_pLblGamerTagStatus->SetText( CBaseModPanel::GetSingleton().GetPartnerDescKey() );
  664. }
  665. }
  666. void VideoPanel::SetPartnerInScienceAlpha( int alpha )
  667. {
  668. if ( m_pWaitingForPlayers )
  669. {
  670. m_pWaitingForPlayers->SetAlpha( alpha );
  671. }
  672. if ( m_pPnlGamerPic )
  673. {
  674. m_pPnlGamerPic->SetAlpha( alpha );
  675. }
  676. if ( m_pLblGamerTag )
  677. {
  678. m_pLblGamerTag->SetAlpha( alpha );
  679. }
  680. if ( m_pLblGamerTagStatus )
  681. {
  682. m_pLblGamerTagStatus->SetAlpha( alpha );
  683. }
  684. }
  685. #endif
  686. void VideoPanel::SetupCaptioning( const char *pFilename, int nPlaybackHeight )
  687. {
  688. if ( m_bIsTransitionVideo )
  689. return;
  690. bool bUseCaptioning = ShouldUseCaptioning();
  691. if ( !bUseCaptioning )
  692. return;
  693. delete m_pSubtitlePanel;
  694. m_pSubtitlePanel = new CSubtitlePanel( this, pFilename, nPlaybackHeight );
  695. // Start the caption sequence
  696. m_pSubtitlePanel->StartCaptions();
  697. }
  698. //-----------------------------------------------------------------------------
  699. // Purpose: Create and playback a video in a panel
  700. // Input : nWidth - Width of panel (in pixels)
  701. // nHeight - Height of panel
  702. // *pVideoFilename - Name of the file to play
  703. // Output : Returns true on success, false on failure.
  704. //-----------------------------------------------------------------------------
  705. bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos,
  706. unsigned int nWidth, unsigned int nHeight,
  707. const char *pVideoFilename,
  708. const char *pExitCommand /*= NULL*/,
  709. int nAllowInterruption /*= 0*/,
  710. float flFadeInTime /*= 1*/,
  711. bool bLoop /*= false*/,
  712. bool bIsTransitionVideo,
  713. bool bAddPartnerUI )
  714. {
  715. // Create the base video panel
  716. VideoPanel *pVideoPanel = new VideoPanel( nXPos, nYPos, nHeight, nWidth );
  717. if ( pVideoPanel == NULL )
  718. return false;
  719. // Toggle if we want the panel to allow interruption
  720. pVideoPanel->SetAllowInterrupt( nAllowInterruption );
  721. // let the panel know that it's a level transition video
  722. pVideoPanel->SetIsTransitionVideo( bIsTransitionVideo );
  723. // Set the command we'll call (if any) when the video is interrupted or completes
  724. pVideoPanel->SetExitCommand( pExitCommand );
  725. pVideoPanel->SetLooping( bLoop );
  726. #if defined( PORTAL2 )
  727. pVideoPanel->EnablePartnerUI( bAddPartnerUI );
  728. #endif
  729. // Start it going
  730. if ( pVideoPanel->BeginPlayback( pVideoFilename ) == false )
  731. {
  732. delete pVideoPanel;
  733. return false;
  734. }
  735. pVideoPanel->SetFadeInTime( flFadeInTime );
  736. // Take control
  737. pVideoPanel->DoModal();
  738. return true;
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose: Take a raw filename and ensure it points to the correct directory and file extension
  742. //-----------------------------------------------------------------------------
  743. void ComposeBinkFilename( const char *lpszFilename, char *lpszOut, int nOutSize )
  744. {
  745. Q_strncpy( lpszOut, "media/", nOutSize ); // Assume we must play out of the media directory
  746. char strFilename[MAX_PATH];
  747. Q_StripExtension( lpszFilename, strFilename, MAX_PATH );
  748. Q_strncat( lpszOut, strFilename, nOutSize );
  749. Q_strncat( lpszOut, ".bik", nOutSize ); // Assume we're a .bik extension type
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Purpose: Create a video panel with the supplied commands
  753. //-----------------------------------------------------------------------------
  754. void CreateVideoPanel( const char *lpszFilename, const char *lpszExitCommand, int nWidth, int nHeight, int nAllowInterruption, float flFadeTime = 0, bool bLoop = false, bool bIsTransitionVideo = false, bool bAddPartnerUI = false )
  755. {
  756. char strFullpath[MAX_PATH];
  757. ComposeBinkFilename( lpszFilename, strFullpath, sizeof(strFullpath) );
  758. // Use the full screen size if they haven't specified an override
  759. unsigned int nScreenWidth = ( nWidth != 0 ) ? nWidth : ScreenWidth();
  760. unsigned int nScreenHeight = ( nHeight != 0 ) ? nHeight : ScreenHeight();
  761. // Create the panel and go!
  762. if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath, lpszExitCommand, nAllowInterruption, flFadeTime, bLoop, bIsTransitionVideo, bAddPartnerUI ) == false )
  763. {
  764. Warning( "Unable to play video: %s\n", strFullpath );
  765. }
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Purpose: Used to launch a video playback
  769. //-----------------------------------------------------------------------------
  770. CON_COMMAND( playvideo, "Plays a video: <filename> [width height]" )
  771. {
  772. if ( args.ArgC() < 2 )
  773. return;
  774. unsigned int nScreenWidth = Q_atoi( args[2] );
  775. unsigned int nScreenHeight = Q_atoi( args[3] );
  776. CreateVideoPanel( args[1], NULL, nScreenWidth, nScreenHeight, VIDEO_ALLOW_INTERRUPT );
  777. }
  778. //-----------------------------------------------------------------------------
  779. // Purpose: Used to launch a video playback
  780. //-----------------------------------------------------------------------------
  781. CON_COMMAND( playvideo_nointerrupt, "Plays a video without ability to skip: <filename> [width height]" )
  782. {
  783. if ( args.ArgC() < 2 )
  784. return;
  785. unsigned int nScreenWidth = Q_atoi( args[2] );
  786. unsigned int nScreenHeight = Q_atoi( args[3] );
  787. CreateVideoPanel( args[1], NULL, nScreenWidth, nScreenHeight, VIDEO_NO_INTERRUPT );
  788. }
  789. //-----------------------------------------------------------------------------
  790. // Purpose: Plays a video fullscreen without ability to skip and fades in
  791. //-----------------------------------------------------------------------------
  792. CON_COMMAND( playvideo_end_level_transition, "Plays a video fullscreen without ability to skip (unless dev 1) and fades in: <filename> <time>" )
  793. {
  794. if ( args.ArgC() < 2 )
  795. return;
  796. float flTime = Q_atoi( args[2] );
  797. if ( flTime <= 0 )
  798. {
  799. Warning( "Fade time needs to be greater than zero! Setting to 0.1f\n" );
  800. flTime = 0.1f;
  801. }
  802. FOR_EACH_VEC( g_vecVideoPanels, itr )
  803. {
  804. if ( g_vecVideoPanels[itr]->IsTransitionVideo() )
  805. {
  806. // We're already playing a transition video... don't start another
  807. return;
  808. }
  809. }
  810. // this con command is only used for the coop transition videos
  811. bool bAddPartnerUI = true;
  812. CreateVideoPanel( args[1], NULL, 0, 0, VIDEO_ALLOW_INTERRUPT_DEV_ONLY, flTime, true, true, bAddPartnerUI );
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose: Used to launch a video playback and fire a command on completion
  816. //-----------------------------------------------------------------------------
  817. CON_COMMAND( playvideo_exitcommand, "Plays a video and fires and exit command when it is stopped or finishes: <filename> <exit command>" )
  818. {
  819. if ( args.ArgC() < 2 )
  820. return;
  821. // Pull out the exit command we want to use
  822. char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] );
  823. CreateVideoPanel( args[1], pExitCommand, 0, 0, VIDEO_ALLOW_INTERRUPT );
  824. }
  825. //-----------------------------------------------------------------------------
  826. // Purpose: Used to launch a video playback and fire a command on completion
  827. //-----------------------------------------------------------------------------
  828. CON_COMMAND( playvideo_exitcommand_nointerrupt, "Plays a video (without interruption) and fires and exit command when it is stopped or finishes: <filename> <exit command>" )
  829. {
  830. if ( args.ArgC() < 2 )
  831. return;
  832. // Pull out the exit command we want to use
  833. char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] );
  834. CreateVideoPanel( args[1], pExitCommand, 0, 0, VIDEO_NO_INTERRUPT );
  835. }
  836. //-----------------------------------------------------------------------------
  837. // Purpose: Cause all playback to stop
  838. //-----------------------------------------------------------------------------
  839. CON_COMMAND( stopvideos, "Stops all videos playing to the screen" )
  840. {
  841. FOR_EACH_VEC( g_vecVideoPanels, itr )
  842. {
  843. g_vecVideoPanels[itr]->StopPlayback();
  844. }
  845. }
  846. //-----------------------------------------------------------------------------
  847. // Purpose: Cause all playback to fade out
  848. //-----------------------------------------------------------------------------
  849. CON_COMMAND( stopvideos_fadeout, "Fades out all videos playing to the screen: <time>" )
  850. {
  851. if ( args.ArgC() < 1 )
  852. return;
  853. float flTime = Q_atoi( args[1] );
  854. if ( flTime <= 0 )
  855. {
  856. Warning( "Fade time needs to be greater than zero! Setting to 0.1f\n" );
  857. flTime = 0.1f;
  858. }
  859. FOR_EACH_VEC( g_vecVideoPanels, itr )
  860. {
  861. g_vecVideoPanels[itr]->SetFadeOutTime( flTime );
  862. }
  863. }
  864. //-----------------------------------------------------------------------------
  865. // Purpose: Cause all transition videos to fade out
  866. //-----------------------------------------------------------------------------
  867. CON_COMMAND( stop_transition_videos_fadeout, "Fades out all transition videos playing to the screen: <time>" )
  868. {
  869. if ( args.ArgC() < 1 )
  870. return;
  871. float flTime = Q_atoi( args[1] );
  872. if ( flTime <= 0 )
  873. {
  874. Warning( "Fade time needs to be greater than zero! Setting to 0.1f\n" );
  875. flTime = 0.1f;
  876. }
  877. FOR_EACH_VEC( g_vecVideoPanels, itr )
  878. {
  879. if ( g_vecVideoPanels[itr]->IsTransitionVideo() )
  880. g_vecVideoPanels[itr]->SetFadeOutTime( flTime );
  881. }
  882. }