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.

527 lines
15 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "cbase.h"
  7. #include "c_vguiscreen.h"
  8. #include "vgui_controls/ImagePanel.h"
  9. #include <vgui/IVGui.h>
  10. #include "ienginevgui.h"
  11. #include "fmtstr.h"
  12. #include "vgui_controls/ImagePanel.h"
  13. #include <vgui/ISurface.h>
  14. #include "avi/ibik.h"
  15. #include "engine/IEngineSound.h"
  16. #include "VGuiMatSurface/IMatSystemSurface.h"
  17. #include "c_movie_display.h"
  18. // NOTE: This has to be the last file included!
  19. #include "tier0/memdbgon.h"
  20. using namespace vgui;
  21. struct VideoPlaybackInfo_t
  22. {
  23. VideoPlaybackInfo_t( void ) :
  24. m_pMaterial ( NULL ),
  25. m_nSourceHeight(0), m_nSourceWidth(0),
  26. m_flU(0.0f),m_flV(0.0f) {}
  27. IMaterial *m_pMaterial;
  28. int m_nSourceHeight, m_nSourceWidth; // Source movie's dimensions
  29. float m_flU, m_flV; // U,V ranges for video on its sheet
  30. };
  31. //-----------------------------------------------------------------------------
  32. // Control screen
  33. //-----------------------------------------------------------------------------
  34. class CMovieDisplayScreen : public CVGuiScreenPanel
  35. {
  36. DECLARE_CLASS( CMovieDisplayScreen, CVGuiScreenPanel );
  37. public:
  38. CMovieDisplayScreen( vgui::Panel *parent, const char *panelName );
  39. ~CMovieDisplayScreen( void );
  40. virtual void ApplySchemeSettings( IScheme *pScheme );
  41. virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
  42. virtual void OnTick( void );
  43. virtual void Paint( void );
  44. private:
  45. bool IsActive( void );
  46. bool IsAGroupPeer( CMovieDisplayScreen* pScreen );
  47. void SetupMovie( void );
  48. void UpdateMovie( void );
  49. bool BeginPlayback( const char *pFilename );
  50. void CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight );
  51. void TakeOverAsMaster();
  52. inline void GetPanelPos( int &xpos, int &ypos )
  53. {
  54. xpos = ( (float) ( GetWide() - m_nPlaybackWidth ) / 2 );
  55. ypos = ( (float) ( GetTall() - m_nPlaybackHeight ) / 2 );
  56. }
  57. private:
  58. // BINK playback info
  59. BIKMaterial_t m_BIKHandle;
  60. VideoPlaybackInfo_t m_playbackInfo;
  61. CHandle<C_VGuiScreen> m_hVGUIScreen;
  62. CHandle<C_MovieDisplay> m_hScreenEntity;
  63. int m_nTextureId;
  64. int m_nPlaybackHeight; // Playback dimensions (proper ration adjustments)
  65. int m_nPlaybackWidth;
  66. bool m_bBlackBackground;
  67. bool m_bSlaved;
  68. bool m_bInitialized;
  69. bool m_bLastActiveState; // HACK: I'd rather get a real callback...
  70. // VGUI specifics
  71. ImagePanel *m_pScanLineImage;
  72. bool bIsAlreadyVisible;
  73. };
  74. DECLARE_VGUI_SCREEN_FACTORY( CMovieDisplayScreen, "movie_display_screen" );
  75. CUtlVector <CMovieDisplayScreen *> g_MovieDisplays;
  76. //-----------------------------------------------------------------------------
  77. // Constructor:
  78. //-----------------------------------------------------------------------------
  79. CMovieDisplayScreen::CMovieDisplayScreen( vgui::Panel *parent, const char *panelName )
  80. : BaseClass( parent, "CMovieDisplayScreen" )
  81. {
  82. m_pScanLineImage = new vgui::ImagePanel( this, "ScanLines");
  83. m_pScanLineImage->SetImage( "elevator_video_lines" );
  84. m_BIKHandle = BIKHANDLE_INVALID;
  85. m_nTextureId = -1;
  86. m_bBlackBackground = true;
  87. m_bSlaved = false;
  88. m_bInitialized = false;
  89. // Add ourselves to the global list of movie displays
  90. g_MovieDisplays.AddToTail( this );
  91. m_bLastActiveState = IsActive();
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose: Clean up the movie
  95. //-----------------------------------------------------------------------------
  96. CMovieDisplayScreen::~CMovieDisplayScreen( void )
  97. {
  98. if ( m_BIKHandle != BIKHANDLE_INVALID )
  99. {
  100. if ( bik )
  101. bik->DestroyMaterial( m_BIKHandle );
  102. m_BIKHandle = BIKHANDLE_INVALID;
  103. }
  104. // Clean up our texture reference
  105. if ( m_nTextureId != -1 )
  106. {
  107. g_pMatSystemSurface->DestroyTextureID( m_nTextureId );
  108. m_nTextureId = -1;
  109. }
  110. // Remove ourselves from the global list of movie displays
  111. g_MovieDisplays.FindAndRemove( this );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: Setup our scheme
  115. //-----------------------------------------------------------------------------
  116. void CMovieDisplayScreen::ApplySchemeSettings( IScheme *pScheme )
  117. {
  118. assert( pScheme );
  119. BaseClass::ApplySchemeSettings(pScheme);
  120. m_pScanLineImage->SetShouldScaleImage( true );
  121. int wide, tall;
  122. this->GetSize( wide, tall );
  123. m_pScanLineImage->SetSize( wide, tall );
  124. m_pScanLineImage->SetDrawColor( Color( 100, 100, 100, 255 ) );
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Initialization
  128. //-----------------------------------------------------------------------------
  129. bool CMovieDisplayScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
  130. {
  131. // Make sure we get ticked...
  132. vgui::ivgui()->AddTickSignal( GetVPanel() );
  133. if ( !BaseClass::Init( pKeyValues, pInitData ) )
  134. return false;
  135. // Save this for simplicity later on
  136. m_hVGUIScreen = dynamic_cast<C_VGuiScreen *>( GetEntity() );
  137. if ( m_hVGUIScreen != NULL )
  138. {
  139. // Also get the associated entity
  140. m_hScreenEntity = dynamic_cast<C_MovieDisplay *>(m_hVGUIScreen->GetOwnerEntity());
  141. }
  142. return true;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose: Helper function to check our active state
  146. //-----------------------------------------------------------------------------
  147. bool CMovieDisplayScreen::IsActive( void )
  148. {
  149. bool bScreenActive = false;
  150. if ( m_hVGUIScreen != NULL )
  151. {
  152. bScreenActive = m_hVGUIScreen->IsActive();
  153. }
  154. return bScreenActive;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: Either become the master of a group of screens, or become a slave to another
  158. //-----------------------------------------------------------------------------
  159. void CMovieDisplayScreen::SetupMovie( void )
  160. {
  161. // Only bother if we haven't been setup yet
  162. if ( m_bInitialized || !IsActive() )
  163. return;
  164. #if defined( _GAMECONSOLE )
  165. Assert( bik );
  166. #endif
  167. if ( !bik )
  168. return;
  169. CMovieDisplayScreen *pMasterScreen = NULL;
  170. for ( int i = 0; i < g_MovieDisplays.Count(); i++ )
  171. {
  172. // Must be a valid peer and not be us
  173. if ( !IsAGroupPeer( g_MovieDisplays[i] ) || g_MovieDisplays[i] == this )
  174. continue;
  175. // See if we've found a master display
  176. if ( g_MovieDisplays[i]->m_bInitialized && g_MovieDisplays[i]->m_bSlaved == false )
  177. {
  178. m_bSlaved = true;
  179. // Share the info from the master
  180. m_playbackInfo = g_MovieDisplays[i]->m_playbackInfo;
  181. // We need to calculate our own playback dimensions as we may be a different size than our parent
  182. CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight );
  183. // Bind our texture
  184. m_nTextureId = surface()->CreateNewTextureID( true );
  185. g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial );
  186. // Hold this as the master screen
  187. pMasterScreen = g_MovieDisplays[i];
  188. break;
  189. }
  190. }
  191. // We need to try again, we have no screen entity!
  192. if ( m_hScreenEntity == NULL )
  193. return;
  194. // No master found, become one
  195. if ( pMasterScreen == NULL && !m_hScreenEntity->IsForcedSlave() )
  196. {
  197. const char *szFilename = m_hScreenEntity->GetMovieFilename();
  198. BeginPlayback( szFilename );
  199. m_bSlaved = false;
  200. m_bInitialized = true; // we are the new master - we are done
  201. }
  202. else if ( pMasterScreen != NULL ) // we are a slave then we are done.
  203. {
  204. m_bInitialized = true;
  205. }
  206. }
  207. bool CMovieDisplayScreen::IsAGroupPeer( CMovieDisplayScreen* pScreen )
  208. {
  209. // Must be valid
  210. if ( pScreen == NULL )
  211. return false;
  212. // Must have an associated movie entity
  213. if ( pScreen->m_hScreenEntity == NULL )
  214. return false;
  215. // Must have a group name to care
  216. const char *szGroupName = m_hScreenEntity->GetGroupName();
  217. if ( szGroupName[0] == NULL )
  218. return false;
  219. // Group names must match!
  220. // FIXME: Use an ID instead?
  221. const char *szTestGroupName = pScreen->m_hScreenEntity->GetGroupName();
  222. if ( Q_strnicmp( szTestGroupName, szGroupName, 128 ) )
  223. return false;
  224. return true;
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose: Try to take over as the master for playback.
  228. //-----------------------------------------------------------------------------
  229. void CMovieDisplayScreen::TakeOverAsMaster( void )
  230. {
  231. // Tell all of the screens that are peers to us that they need to be set up again
  232. for ( int i = 0; i < g_MovieDisplays.Count(); i++ )
  233. {
  234. if ( IsAGroupPeer( g_MovieDisplays[i] ) )
  235. {
  236. if ( g_MovieDisplays[i]->m_nTextureId != -1 )
  237. {
  238. g_pMatSystemSurface->DestroyTextureID( g_MovieDisplays[i]->m_nTextureId );
  239. g_MovieDisplays[i]->m_nTextureId = -1;
  240. }
  241. // make it so we will reinitialize ourselves.
  242. g_MovieDisplays[i]->m_bInitialized = false;
  243. }
  244. }
  245. // Even if we don't become the master we should stop trying
  246. m_hScreenEntity->SetMasterAttempted();
  247. SetupMovie();
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: Deal with the details of the video playback
  251. //-----------------------------------------------------------------------------
  252. void CMovieDisplayScreen::UpdateMovie( void )
  253. {
  254. // Only the master in a group updates the bink file
  255. if ( m_bSlaved )
  256. return;
  257. // Must have a movie to play
  258. if ( m_BIKHandle == BIKHANDLE_INVALID )
  259. return;
  260. // Get the current activity state of the screen
  261. bool bScreenActive = IsActive();
  262. // Pause if the game has paused
  263. bool bPaused = ( engine->IsPaused() || engine->Con_IsVisible() );
  264. if ( bPaused )
  265. {
  266. bScreenActive = false;
  267. }
  268. // See if we've changed our activity state
  269. if ( bik && bScreenActive != m_bLastActiveState )
  270. {
  271. if ( bScreenActive )
  272. {
  273. if ( /*m_bRestartOnResume*/ 1 && !bPaused )
  274. {
  275. bik->SetFrame( m_BIKHandle, 1.0f );
  276. }
  277. bik->Unpause( m_BIKHandle );
  278. }
  279. else
  280. {
  281. bik->Pause( m_BIKHandle );
  282. }
  283. }
  284. // Updated
  285. m_bLastActiveState = bScreenActive;
  286. // Update the frame if we're currently enabled
  287. if ( bScreenActive )
  288. {
  289. // Update our frame
  290. if ( bik && bik->Update( m_BIKHandle ) == false )
  291. {
  292. // Issue a close command
  293. // OnVideoOver();
  294. // StopPlayback();
  295. }
  296. }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Update the display string
  300. //-----------------------------------------------------------------------------
  301. void CMovieDisplayScreen::OnTick()
  302. {
  303. BaseClass::OnTick();
  304. if( m_hScreenEntity && m_hScreenEntity->GetWantsToBeMaster() )
  305. {
  306. TakeOverAsMaster();
  307. }
  308. // Create our playback or slave to another screen already playing
  309. SetupMovie();
  310. // Now update the movie
  311. UpdateMovie();
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose: Adjust the playback dimensions to properly account for our screen dimensions
  315. //-----------------------------------------------------------------------------
  316. void CMovieDisplayScreen::CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight )
  317. {
  318. // Change our stretching type
  319. if ( m_hScreenEntity && m_hScreenEntity->IsStretchingToFill() )
  320. {
  321. m_nPlaybackWidth = GetWide();
  322. m_nPlaybackHeight = GetTall();
  323. return;
  324. }
  325. float flFrameRatio = ( (float) GetWide() / (float) GetTall() );
  326. float flVideoRatio = ( (float) nSrcWidth / (float) nSrcHeight );
  327. if ( flVideoRatio > flFrameRatio )
  328. {
  329. m_nPlaybackWidth = GetWide();
  330. m_nPlaybackHeight = ( GetWide() / flVideoRatio );
  331. }
  332. else if ( flVideoRatio < flFrameRatio )
  333. {
  334. m_nPlaybackWidth = ( GetTall() * flVideoRatio );
  335. m_nPlaybackHeight = GetTall();
  336. }
  337. else
  338. {
  339. m_nPlaybackWidth = GetWide();
  340. m_nPlaybackHeight = GetTall();
  341. }
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Begins playback of a movie
  345. // Output : Returns true on success, false on failure.
  346. //-----------------------------------------------------------------------------
  347. bool CMovieDisplayScreen::BeginPlayback( const char *pFilename )
  348. {
  349. #if defined( _GAMECONSOLE )
  350. Assert( bik );
  351. #endif
  352. if ( !bik )
  353. return false;
  354. if ( m_BIKHandle == BIKHANDLE_INVALID )
  355. {
  356. // Create a globally unique name for this material
  357. char szMaterialName[256];
  358. // Append our group name if we have one
  359. const char *szGroupName = m_hScreenEntity->GetGroupName();
  360. if ( szGroupName[0] != NULL )
  361. {
  362. Q_snprintf( szMaterialName, sizeof(szMaterialName), "%s_%s", pFilename, szGroupName );
  363. }
  364. else
  365. {
  366. Q_strncpy( szMaterialName, pFilename, sizeof(szMaterialName) );
  367. }
  368. // Load and create our BINK video
  369. int nFlags = BIK_NO_AUDIO; // FIXME: Allow?
  370. nFlags |= BIK_PRELOAD;
  371. if ( m_hScreenEntity->IsLooping() )
  372. {
  373. nFlags |= BIK_LOOP;
  374. }
  375. if ( bik )
  376. m_BIKHandle = bik->CreateMaterial( szMaterialName, pFilename, "GAME", nFlags );
  377. if ( m_BIKHandle == BIKHANDLE_INVALID )
  378. return false;
  379. }
  380. // NOTE: This class shouldn't turn off all sounds (Bank)
  381. //if ( ( nFlags & BIK_NO_AUDIO ) != 0 )
  382. //{
  383. // // We want to be the sole audio source
  384. // enginesound->NotifyBeginMoviePlayback();
  385. //}
  386. // Get our basic info from the movie
  387. bik->GetFrameSize( m_BIKHandle, &m_playbackInfo.m_nSourceWidth, &m_playbackInfo.m_nSourceHeight );
  388. bik->GetTexCoordRange( m_BIKHandle, &m_playbackInfo.m_flU, &m_playbackInfo.m_flV );
  389. m_playbackInfo.m_pMaterial = bik->GetMaterial( m_BIKHandle );
  390. // Get our playback dimensions
  391. CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight );
  392. // Bind our texture
  393. m_nTextureId = surface()->CreateNewTextureID( true );
  394. g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial );
  395. return true;
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Purpose: Update and draw the frame
  399. //-----------------------------------------------------------------------------
  400. void CMovieDisplayScreen::Paint( void )
  401. {
  402. // Masters must keep the video updated
  403. if ( m_bSlaved == false && m_BIKHandle == BIKHANDLE_INVALID )
  404. {
  405. BaseClass::Paint();
  406. return;
  407. }
  408. // Sit in the "center"
  409. int xpos, ypos;
  410. GetPanelPos( xpos, ypos );
  411. bool bStretchToFill = ( m_hScreenEntity != NULL ) ? m_hScreenEntity->IsStretchingToFill() : false;
  412. bool bUsingCustomUVs = ( m_hScreenEntity != NULL ) ? m_hScreenEntity->IsUsingCustomUVs() : false;
  413. // Black out the background (we could omit drawing under the video surface, but this is straight-forward)
  414. if ( m_bBlackBackground && !bStretchToFill )
  415. {
  416. surface()->DrawSetColor( 0, 0, 0, 255 );
  417. surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
  418. }
  419. // Draw it
  420. surface()->DrawSetTexture( m_nTextureId );
  421. surface()->DrawSetColor( 255, 255, 255, 255 );
  422. if ( bUsingCustomUVs )
  423. {
  424. surface()->DrawTexturedSubRect( xpos, ypos, xpos+m_nPlaybackWidth, ypos+m_nPlaybackHeight,
  425. m_hScreenEntity->GetUMin(),
  426. m_hScreenEntity->GetVMin(),
  427. m_hScreenEntity->GetUMax(),
  428. m_hScreenEntity->GetVMax() );
  429. }
  430. else
  431. {
  432. surface()->DrawTexturedSubRect( xpos, ypos, xpos+m_nPlaybackWidth, ypos+m_nPlaybackHeight, 0.f, 0.f, m_playbackInfo.m_flU, m_playbackInfo.m_flV );
  433. }
  434. // Parent's turn
  435. BaseClass::Paint();
  436. }