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.

2676 lines
81 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #if defined( USE_SDL )
  7. #undef PROTECTED_THINGS_ENABLE
  8. #include "SDL.h"
  9. #include "SDL_syswm.h"
  10. #endif
  11. #if defined( _WIN32 ) && !defined( _X360 )
  12. #include "winlite.h"
  13. #elif defined(POSIX)
  14. typedef void *HDC;
  15. #endif
  16. #include "appframework/ilaunchermgr.h"
  17. #include "basetypes.h"
  18. #include "sysexternal.h"
  19. #include "cmd.h"
  20. #include "modelloader.h"
  21. #include "gl_matsysiface.h"
  22. #include "vmodes.h"
  23. #include "modes.h"
  24. #include "ivideomode.h"
  25. #include "igame.h"
  26. #include "iengine.h"
  27. #include "engine_launcher_api.h"
  28. #include "iregistry.h"
  29. #include "common.h"
  30. #include "tier0/icommandline.h"
  31. #include "cl_main.h"
  32. #include "filesystem_engine.h"
  33. #include "host.h"
  34. #include "gl_model_private.h"
  35. #include "bitmap/tgawriter.h"
  36. #include "vtf/vtf.h"
  37. #include "materialsystem/materialsystem_config.h"
  38. #include "materialsystem/itexture.h"
  39. #include "materialsystem/imaterialsystemhardwareconfig.h"
  40. #include "jpeglib/jpeglib.h"
  41. #include "vgui/ISurface.h"
  42. #include "vgui_controls/Controls.h"
  43. #include "gl_shader.h"
  44. #include "sys_dll.h"
  45. #include "materialsystem/imaterial.h"
  46. #include "IHammer.h"
  47. #include "sourcevr/isourcevirtualreality.h"
  48. #include "tier2/tier2.h"
  49. #include "tier2/renderutils.h"
  50. #include "tier0/etwprof.h"
  51. #if defined( _X360 )
  52. #include "xbox/xbox_win32stubs.h"
  53. #else
  54. #include "xbox/xboxstubs.h"
  55. #endif
  56. #include "video/ivideoservices.h"
  57. #if !defined(NO_STEAM)
  58. #include "cl_steamauth.h"
  59. #endif
  60. // memdbgon must be the last include file in a .cpp file!!!
  61. #include "tier0/memdbgon.h"
  62. //-----------------------------------------------------------------------------
  63. void CL_GetBackgroundLevelName(char *pszBackgroundName, int bufSize, bool bMapName);
  64. void ClientDLL_HudVidInit( void );
  65. ConVar cl_savescreenshotstosteam( "cl_savescreenshotstosteam", "0", FCVAR_HIDDEN, "Saves screenshots to the Steam's screenshot library" );
  66. ConVar cl_screenshotusertag( "cl_screenshotusertag", "", FCVAR_HIDDEN, "User to tag in the screenshot" );
  67. ConVar cl_screenshotlocation( "cl_screenshotlocation", "", FCVAR_HIDDEN, "Location to tag the screenshot with" );
  68. //-----------------------------------------------------------------------------
  69. // HDRFIXME: move this somewhere else.
  70. //-----------------------------------------------------------------------------
  71. static void PFMWrite( float *pFloatImage, const char *pFilename, int width, int height )
  72. {
  73. FileHandle_t fp;
  74. fp = g_pFileSystem->Open( pFilename, "wb" );
  75. g_pFileSystem->FPrintf( fp, "PF\n%d %d\n-1.000000\n", width, height );
  76. int i;
  77. for( i = height-1; i >= 0; i-- )
  78. {
  79. float *pRow = &pFloatImage[3 * width * i];
  80. g_pFileSystem->Write( pRow, width * sizeof( float ) * 3, fp );
  81. }
  82. g_pFileSystem->Close( fp );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose: Functionality shared by all video modes
  86. //-----------------------------------------------------------------------------
  87. class CVideoMode_Common : public IVideoMode
  88. {
  89. public:
  90. CVideoMode_Common( void );
  91. virtual ~CVideoMode_Common( void );
  92. // Methods of IVideoMode
  93. virtual bool Init( );
  94. virtual void Shutdown( void );
  95. virtual vmode_t *GetMode( int num );
  96. virtual int GetModeCount( void );
  97. virtual bool IsWindowedMode( void ) const;
  98. virtual void UpdateWindowPosition( void );
  99. virtual void RestoreVideo( void );
  100. virtual void ReleaseVideo( void );
  101. virtual void DrawNullBackground( void *hdc, int w, int h );
  102. virtual void InvalidateWindow();
  103. virtual void DrawStartupGraphic();
  104. virtual bool CreateGameWindow( int nWidth, int nHeight, bool bWindowed );
  105. virtual int GetModeWidth( void ) const;
  106. virtual int GetModeHeight( void ) const;
  107. virtual int GetModeStereoWidth() const;
  108. virtual int GetModeStereoHeight() const;
  109. virtual int GetModeUIWidth() const OVERRIDE;
  110. virtual int GetModeUIHeight() const OVERRIDE;
  111. virtual const vrect_t &GetClientViewRect( ) const;
  112. virtual void SetClientViewRect( const vrect_t &viewRect );
  113. virtual void MarkClientViewRectDirty();
  114. virtual void TakeSnapshotTGA( const char *pFileName );
  115. virtual void TakeSnapshotTGARect( const char *pFilename, int x, int y, int w, int h, int resampleWidth, int resampleHeight, bool bPFM, CubeMapFaceIndex_t faceIndex );
  116. virtual void WriteMovieFrame( const MovieInfo_t& info );
  117. virtual void TakeSnapshotJPEG( const char *pFileName, int quality );
  118. virtual bool TakeSnapshotJPEGToBuffer( CUtlBuffer& buf, int quality );
  119. protected:
  120. bool GetInitialized( ) const;
  121. void SetInitialized( bool init );
  122. void AdjustWindow( int nWidth, int nHeight, int nBPP, bool bWindowed );
  123. void ResetCurrentModeForNewResolution( int width, int height, bool bWindowed );
  124. int GetModeBPP( ) const { return 32; }
  125. void DrawStartupVideo();
  126. void ComputeStartupGraphicName( char *pBuf, int nBufLen );
  127. void WriteScreenshotToSteam( uint8 *pImage, int cubImage, int width, int height );
  128. void AddScreenshotToSteam( const char *pchFilenameJpeg, int width, int height );
  129. #if !defined(NO_STEAM)
  130. void ApplySteamScreenshotTags( ScreenshotHandle hScreenshot );
  131. #endif
  132. // Finds the video mode in the list of video modes
  133. int FindVideoMode( int nDesiredWidth, int nDesiredHeight, bool bWindowed );
  134. // Purpose: Returns the optimal refresh rate for the specified mode
  135. int GetRefreshRateForMode( const vmode_t *pMode );
  136. // Inline accessors
  137. vmode_t& DefaultVideoMode();
  138. vmode_t& RequestedWindowVideoMode();
  139. private:
  140. // Purpose: Loads the startup graphic
  141. void SetupStartupGraphic();
  142. void CenterEngineWindow(void *hWndCenter, int width, int height);
  143. void DrawStartupGraphic( HWND window );
  144. void BlitGraphicToHDC(HDC hdc, byte *rgba, int imageWidth, int imageHeight, int x0, int y0, int x1, int y1);
  145. void BlitGraphicToHDCWithAlpha(HDC hdc, byte *rgba, int imageWidth, int imageHeight, int x0, int y0, int x1, int y1);
  146. IVTFTexture *LoadVTF( CUtlBuffer &temp, const char *szFileName );
  147. void RecomputeClientViewRect();
  148. // Overridden by derived classes
  149. virtual void ReleaseFullScreen( void );
  150. virtual void ChangeDisplaySettingsToFullscreen( int nWidth, int nHeight, int nBPP );
  151. virtual void ReadScreenPixels( int x, int y, int w, int h, void *pBuffer, ImageFormat format );
  152. // PFM screenshot methods
  153. ITexture *GetBuildCubemaps16BitTexture( void );
  154. ITexture *GetFullFrameFB0( void );
  155. void BlitHiLoScreenBuffersTo16Bit( void );
  156. void TakeSnapshotPFMRect( const char *pFilename, int x, int y, int w, int h, int resampleWidth, int resampleHeight, CubeMapFaceIndex_t faceIndex );
  157. protected:
  158. enum
  159. {
  160. #if !defined( _X360 )
  161. MAX_MODE_LIST = 512
  162. #else
  163. MAX_MODE_LIST = 2
  164. #endif
  165. };
  166. enum
  167. {
  168. VIDEO_MODE_DEFAULT = -1,
  169. VIDEO_MODE_REQUESTED_WINDOW_SIZE = -2,
  170. CUSTOM_VIDEO_MODES = 2
  171. };
  172. // Master mode list
  173. int m_nNumModes;
  174. vmode_t m_rgModeList[MAX_MODE_LIST];
  175. vmode_t m_nCustomModeList[CUSTOM_VIDEO_MODES];
  176. bool m_bInitialized;
  177. bool m_bPlayedStartupVideo;
  178. // Renderable surface information
  179. int m_nModeWidth;
  180. int m_nModeHeight;
  181. int m_nStereoWidth;
  182. int m_nStereoHeight;
  183. int m_nUIWidth;
  184. int m_nUIHeight;
  185. int m_nVROverrideX;
  186. int m_nVROverrideY;
  187. #if defined( USE_SDL )
  188. int m_nRenderWidth;
  189. int m_nRenderHeight;
  190. #endif
  191. bool m_bWindowed;
  192. bool m_bSetModeOnce;
  193. bool m_bVROverride;
  194. // Client view rectangle
  195. vrect_t m_ClientViewRect;
  196. bool m_bClientViewRectDirty;
  197. // loading image
  198. IVTFTexture *m_pBackgroundTexture;
  199. IVTFTexture *m_pLoadingTexture;
  200. };
  201. //-----------------------------------------------------------------------------
  202. // Inline accessors
  203. //-----------------------------------------------------------------------------
  204. inline vmode_t& CVideoMode_Common::DefaultVideoMode()
  205. {
  206. return m_nCustomModeList[ - VIDEO_MODE_DEFAULT - 1 ];
  207. }
  208. inline vmode_t& CVideoMode_Common::RequestedWindowVideoMode()
  209. {
  210. return m_nCustomModeList[ - VIDEO_MODE_REQUESTED_WINDOW_SIZE - 1 ];
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose:
  214. //-----------------------------------------------------------------------------
  215. CVideoMode_Common::CVideoMode_Common( void )
  216. {
  217. m_nNumModes = 0;
  218. m_bInitialized = false;
  219. DefaultVideoMode().width = 640;
  220. DefaultVideoMode().height = 480;
  221. DefaultVideoMode().bpp = 32;
  222. DefaultVideoMode().refreshRate = 0;
  223. RequestedWindowVideoMode().width = -1;
  224. RequestedWindowVideoMode().height = -1;
  225. RequestedWindowVideoMode().bpp = 32;
  226. RequestedWindowVideoMode().refreshRate = 0;
  227. m_bClientViewRectDirty = false;
  228. m_pBackgroundTexture = NULL;
  229. m_pLoadingTexture = NULL;
  230. m_bWindowed = false;
  231. m_nModeWidth = IsPC() ? 1024 : 640;
  232. m_nModeHeight = IsPC() ? 768 : 480;
  233. m_bVROverride = false;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose:
  237. //-----------------------------------------------------------------------------
  238. CVideoMode_Common::~CVideoMode_Common( void )
  239. {
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. // Output : Returns true on success, false on failure.
  244. //-----------------------------------------------------------------------------
  245. bool CVideoMode_Common::GetInitialized( void ) const
  246. {
  247. return m_bInitialized;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose:
  251. // Input : init -
  252. //-----------------------------------------------------------------------------
  253. void CVideoMode_Common::SetInitialized( bool init )
  254. {
  255. m_bInitialized = init;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. // Output : Returns true on success, false on failure.
  260. //-----------------------------------------------------------------------------
  261. bool CVideoMode_Common::IsWindowedMode( void ) const
  262. {
  263. return m_bWindowed;
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Returns the video mode width + height.
  267. //-----------------------------------------------------------------------------
  268. int CVideoMode_Common::GetModeWidth( void ) const
  269. {
  270. return m_nModeWidth;
  271. }
  272. int CVideoMode_Common::GetModeHeight( void ) const
  273. {
  274. return m_nModeHeight;
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Returns the video mode width + height for one stereo view.
  278. //-----------------------------------------------------------------------------
  279. int CVideoMode_Common::GetModeStereoWidth( void ) const
  280. {
  281. return m_nStereoWidth;
  282. }
  283. int CVideoMode_Common::GetModeStereoHeight( void ) const
  284. {
  285. return m_nStereoHeight;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Returns the video mode full screen UI width + height.
  289. //-----------------------------------------------------------------------------
  290. int CVideoMode_Common::GetModeUIWidth( void ) const
  291. {
  292. return m_nUIWidth;
  293. }
  294. int CVideoMode_Common::GetModeUIHeight( void ) const
  295. {
  296. return m_nUIHeight;
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Returns the enumerated video mode
  300. //-----------------------------------------------------------------------------
  301. vmode_t *CVideoMode_Common::GetMode( int num )
  302. {
  303. if ( num < 0 )
  304. return &m_nCustomModeList[-num - 1];
  305. if ( num >= m_nNumModes )
  306. return &DefaultVideoMode();
  307. return &m_rgModeList[num];
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Returns the number of fullscreen video modes
  311. //-----------------------------------------------------------------------------
  312. int CVideoMode_Common::GetModeCount( void )
  313. {
  314. return m_nNumModes;
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Compares video modes so we can sort the list
  318. // Input : *arg1 -
  319. // *arg2 -
  320. // Output : static int
  321. //-----------------------------------------------------------------------------
  322. static int __cdecl VideoModeCompare( const void *arg1, const void *arg2 )
  323. {
  324. vmode_t *m1, *m2;
  325. m1 = (vmode_t *)arg1;
  326. m2 = (vmode_t *)arg2;
  327. if ( m1->width < m2->width )
  328. {
  329. return -1;
  330. }
  331. if ( m1->width == m2->width )
  332. {
  333. if ( m1->height < m2->height )
  334. {
  335. return -1;
  336. }
  337. if ( m1->height > m2->height )
  338. {
  339. return 1;
  340. }
  341. return 0;
  342. }
  343. return 1;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Purpose:
  347. //-----------------------------------------------------------------------------
  348. bool CVideoMode_Common::Init( )
  349. {
  350. return true;
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Finds the video mode in the list of video modes
  354. //-----------------------------------------------------------------------------
  355. int CVideoMode_Common::FindVideoMode( int nDesiredWidth, int nDesiredHeight, bool bWindowed )
  356. {
  357. #if defined( USE_SDL )
  358. // If we want to scale the 3D portion of the game and leave the UI at the same res, then
  359. // re-enable this code. Not that on retina displays the UI will be super small and that
  360. // should probably be fixed.
  361. #if 0
  362. static ConVarRef mat_viewportscale( "mat_viewportscale" );
  363. if ( !bWindowed )
  364. {
  365. m_nRenderWidth = nDesiredWidth;
  366. m_nRenderHeight = nDesiredHeight;
  367. uint nWidth, nHeight, nRefreshHz;
  368. g_pLauncherMgr->GetNativeDisplayInfo( -1, nWidth, nHeight, nRefreshHz );
  369. for ( int i = 0; i < m_nNumModes; i++)
  370. {
  371. if ( m_rgModeList[i].width != ( int )nWidth )
  372. {
  373. continue;
  374. }
  375. if ( m_rgModeList[i].height != ( int )nHeight )
  376. {
  377. continue;
  378. }
  379. if ( m_rgModeList[i].refreshRate != ( int )nRefreshHz )
  380. {
  381. continue;
  382. }
  383. mat_viewportscale.SetValue( ( float )nDesiredWidth / ( float )nWidth );
  384. return i;
  385. }
  386. Assert( 0 ); // we should have found our native resolution, why not???
  387. }
  388. else
  389. {
  390. mat_viewportscale.SetValue( 1.0f );
  391. }
  392. #endif // 0
  393. #endif // USE_SDL
  394. // Check the default window size..
  395. if ( ( nDesiredWidth == DefaultVideoMode().width) && (nDesiredHeight == DefaultVideoMode().height) )
  396. return VIDEO_MODE_DEFAULT;
  397. // Check the requested window size, but only if we're running windowed
  398. if ( bWindowed )
  399. {
  400. if ( ( nDesiredWidth == RequestedWindowVideoMode().width) && (nDesiredHeight == RequestedWindowVideoMode().height) )
  401. return VIDEO_MODE_REQUESTED_WINDOW_SIZE;
  402. }
  403. int i;
  404. int iOK = VIDEO_MODE_DEFAULT;
  405. for ( i = 0; i < m_nNumModes; i++)
  406. {
  407. // Match width first
  408. if ( m_rgModeList[i].width != nDesiredWidth )
  409. continue;
  410. iOK = i;
  411. if ( m_rgModeList[i].height != nDesiredHeight )
  412. continue;
  413. // Found a decent match
  414. break;
  415. }
  416. // No match, use mode 0
  417. if ( i >= m_nNumModes )
  418. {
  419. if ( iOK != VIDEO_MODE_DEFAULT )
  420. {
  421. i = iOK;
  422. }
  423. else
  424. {
  425. i = 0;
  426. }
  427. }
  428. return i;
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Choose the actual video mode based on the available modes
  432. //-----------------------------------------------------------------------------
  433. void CVideoMode_Common::ResetCurrentModeForNewResolution( int nWidth, int nHeight, bool bWindowed )
  434. {
  435. // Fill in vid structure for the mode
  436. int nGameMode = FindVideoMode( nWidth, nHeight, bWindowed );
  437. vmode_t *pMode = GetMode( nGameMode );
  438. // default to non-VR values
  439. m_bWindowed = bWindowed;
  440. m_nModeWidth = pMode->width;
  441. m_nModeHeight = pMode->height;
  442. m_nUIWidth = pMode->width;
  443. m_nUIHeight = pMode->height;
  444. m_nStereoWidth = pMode->width;
  445. m_nStereoHeight = pMode->height;
  446. // assume we won't be overriding the position
  447. m_bVROverride = false;
  448. if ( UseVR() || ShouldForceVRActive() )
  449. {
  450. g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, NULL, NULL, &m_nStereoWidth, &m_nStereoHeight );
  451. VRRect_t vrBounds;
  452. if( g_pSourceVR->GetDisplayBounds( &vrBounds ) )
  453. {
  454. ConVarRef vr_force_windowed( "vr_force_windowed" );
  455. RequestedWindowVideoMode().width = m_nModeWidth = vrBounds.nWidth;
  456. RequestedWindowVideoMode().height = m_nModeHeight = vrBounds.nHeight;
  457. m_bVROverride = true;
  458. m_bWindowed = vr_force_windowed.GetBool();
  459. // This is the smallest size the the UI in source games can handle.
  460. m_nUIWidth = 640;
  461. m_nUIHeight = 480;
  462. #if defined( WIN32 ) && !defined( USE_SDL )
  463. m_nVROverrideX = vrBounds.nX;
  464. m_nVROverrideY = vrBounds.nY;
  465. #elif defined( USE_SDL )
  466. for ( int i = 0; i < SDL_GetNumVideoDisplays(); i++ )
  467. {
  468. SDL_Rect sdlRect;
  469. SDL_GetDisplayBounds( i, &sdlRect );
  470. if( sdlRect.x == vrBounds.nX && sdlRect.y == vrBounds.nY
  471. && sdlRect.w == vrBounds.nWidth && sdlRect.h == vrBounds.nHeight )
  472. {
  473. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  474. sdl_displayindex.SetValue( i );
  475. break;
  476. }
  477. }
  478. #endif
  479. }
  480. }
  481. else if( materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter() )
  482. {
  483. // if we aren't in VR mode but we do have a VR mode adapter set, we must not be full
  484. // screen because that would show up on the HMD
  485. m_bWindowed = true;
  486. }
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Creates the game window, plays the startup movie
  490. //-----------------------------------------------------------------------------
  491. bool CVideoMode_Common::CreateGameWindow( int nWidth, int nHeight, bool bWindowed )
  492. {
  493. COM_TimestampedLog( "CVideoMode_Common::Init CreateGameWindow" );
  494. if ( ShouldForceVRActive() )
  495. {
  496. // First make sure we're running a compatible version of DirectX
  497. ConVarRef mat_dxlevel( "mat_dxlevel" );
  498. if ( mat_dxlevel.IsValid() )
  499. {
  500. if ( mat_dxlevel.GetInt() < 90 )
  501. {
  502. Msg( "VR mode does not work with DirectX8.\nPlease use at least \"-dxlevel 90\" or higher.\n" );
  503. return false;
  504. }
  505. }
  506. VRRect_t bounds;
  507. g_pSourceVR->GetDisplayBounds( &bounds );
  508. nWidth = bounds.nWidth;
  509. nHeight = bounds.nHeight;
  510. m_nVROverrideX = bounds.nX;
  511. m_nVROverrideY = bounds.nY;
  512. }
  513. // This allows you to have a window of any size.
  514. // Requires you to set both width and height for the window and
  515. // that you start in windowed mode
  516. if ( bWindowed && nWidth && nHeight )
  517. {
  518. // FIXME: There's some ordering issues related to the config record
  519. // and reading the command-line. Would be nice for just one place where this is done.
  520. RequestedWindowVideoMode().width = nWidth;
  521. RequestedWindowVideoMode().height = nHeight;
  522. }
  523. if ( !InEditMode() )
  524. {
  525. // Fill in vid structure for the mode.
  526. // Note: ModeWidth/Height may *not* match requested nWidth/nHeight
  527. ResetCurrentModeForNewResolution( nWidth, nHeight, bWindowed );
  528. COM_TimestampedLog( "CreateGameWindow - Start" );
  529. // When running in stand-alone mode, create your own window
  530. if ( !game->CreateGameWindow() )
  531. return false;
  532. COM_TimestampedLog( "CreateGameWindow - Finish" );
  533. // Re-size and re-center the window
  534. AdjustWindow( GetModeWidth(), GetModeHeight(), GetModeBPP(), IsWindowedMode() );
  535. COM_TimestampedLog( "SetMode - Start" );
  536. // Set the mode and let the materialsystem take over
  537. if ( !SetMode( GetModeWidth(), GetModeHeight(), IsWindowedMode() ) )
  538. return false;
  539. #if defined( USE_SDL ) && 0
  540. static ConVarRef mat_viewportscale( "mat_viewportscale" );
  541. if ( !bWindowed )
  542. {
  543. m_nRenderWidth = nWidth;
  544. m_nRenderHeight = nHeight;
  545. mat_viewportscale.SetValue( ( float )nWidth / ( float )GetModeWidth() );
  546. }
  547. #endif
  548. COM_TimestampedLog( "SetMode - Finish" );
  549. // Play our videos for the background after the render device has been initialized
  550. DrawStartupVideo();
  551. COM_TimestampedLog( "DrawStartupGraphic - Start" );
  552. // Play our videos or display our temp image for the background
  553. DrawStartupGraphic();
  554. COM_TimestampedLog( "DrawStartupGraphic - Finish" );
  555. }
  556. return true;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose: loads a vtf, through the temporary buffer
  560. //-----------------------------------------------------------------------------
  561. IVTFTexture *CVideoMode_Common::LoadVTF( CUtlBuffer &temp, const char *szFileName )
  562. {
  563. if ( !g_pFileSystem->ReadFile( szFileName, NULL, temp ) )
  564. return NULL;
  565. IVTFTexture *texture = CreateVTFTexture();
  566. if ( !texture->Unserialize( temp ) )
  567. {
  568. Error( "Invalid or corrupt background texture %s\n", szFileName );
  569. return NULL;
  570. }
  571. texture->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false );
  572. return texture;
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Computes the startup graphic name
  576. //-----------------------------------------------------------------------------
  577. void CVideoMode_Common::ComputeStartupGraphicName( char *pBuf, int nBufLen )
  578. {
  579. char szBackgroundName[_MAX_PATH];
  580. CL_GetBackgroundLevelName( szBackgroundName, sizeof(szBackgroundName), false );
  581. float aspectRatio = (float)GetModeStereoWidth() / GetModeStereoHeight();
  582. if ( aspectRatio >= 1.6f )
  583. {
  584. // use the widescreen version
  585. Q_snprintf( pBuf, nBufLen, "materials/console/%s_widescreen.vtf", szBackgroundName );
  586. }
  587. else
  588. {
  589. Q_snprintf( pBuf, nBufLen, "materials/console/%s.vtf", szBackgroundName );
  590. }
  591. if ( !g_pFileSystem->FileExists( pBuf, "GAME" ) )
  592. {
  593. Q_strncpy( pBuf, ( aspectRatio >= 1.6f ) ? "materials/console/background01_widescreen.vtf" : "materials/console/background01.vtf", nBufLen );
  594. }
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Writes a screenshot to Steam screenshot library given an RGB buffer
  598. // and applies any tags that have been set for it
  599. //-----------------------------------------------------------------------------
  600. void CVideoMode_Common::WriteScreenshotToSteam( uint8 *pImage, int cubImage, int width, int height )
  601. {
  602. #if !defined(NO_STEAM)
  603. if ( cl_savescreenshotstosteam.GetBool() )
  604. {
  605. if ( Steam3Client().SteamScreenshots() )
  606. {
  607. ScreenshotHandle hScreenshot = Steam3Client().SteamScreenshots()->WriteScreenshot( pImage, cubImage, width, height );
  608. ApplySteamScreenshotTags( hScreenshot );
  609. }
  610. }
  611. cl_screenshotusertag.SetValue(0);
  612. cl_screenshotlocation.SetValue("");
  613. #endif
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Adds a screenshot to the Steam screenshot library from disk
  617. // and applies any tags that have been set for it
  618. //-----------------------------------------------------------------------------
  619. void CVideoMode_Common::AddScreenshotToSteam( const char *pchFilename, int width, int height )
  620. {
  621. #if !defined(NO_STEAM)
  622. if ( cl_savescreenshotstosteam.GetBool() )
  623. {
  624. if ( Steam3Client().SteamScreenshots() )
  625. {
  626. ScreenshotHandle hScreenshot = Steam3Client().SteamScreenshots()->AddScreenshotToLibrary( pchFilename, NULL, width, height );
  627. ApplySteamScreenshotTags( hScreenshot );
  628. }
  629. }
  630. cl_screenshotusertag.SetValue(0);
  631. cl_screenshotlocation.SetValue("");
  632. #endif
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Applies tags to a screenshot for the Steam screenshot library, which are
  636. // passed in through convars
  637. //-----------------------------------------------------------------------------
  638. #if !defined(NO_STEAM)
  639. void CVideoMode_Common::ApplySteamScreenshotTags( ScreenshotHandle hScreenshot )
  640. {
  641. if ( hScreenshot != INVALID_SCREENSHOT_HANDLE )
  642. {
  643. if ( cl_screenshotusertag.GetBool() )
  644. {
  645. if ( Steam3Client().SteamUtils() )
  646. {
  647. CSteamID steamID( cl_screenshotusertag.GetInt(), Steam3Client().SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
  648. Steam3Client().SteamScreenshots()->TagUser( hScreenshot, steamID );
  649. }
  650. }
  651. const char *pchLocation = cl_screenshotlocation.GetString();
  652. if ( pchLocation && pchLocation[0] )
  653. {
  654. Steam3Client().SteamScreenshots()->SetLocation( hScreenshot, pchLocation );
  655. }
  656. }
  657. }
  658. #endif
  659. void CVideoMode_Common::SetupStartupGraphic()
  660. {
  661. COM_TimestampedLog( "CVideoMode_Common::Init SetupStartupGraphic" );
  662. char szBackgroundName[_MAX_PATH];
  663. CL_GetBackgroundLevelName( szBackgroundName, sizeof(szBackgroundName), false );
  664. // get the image to load
  665. char material[_MAX_PATH];
  666. CUtlBuffer buf;
  667. float aspectRatio = (float)GetModeWidth() / GetModeHeight();
  668. if ( aspectRatio >= 1.6f )
  669. {
  670. // use the widescreen version
  671. Q_snprintf( material, sizeof(material),
  672. "materials/console/%s_widescreen.vtf", szBackgroundName );
  673. }
  674. else
  675. {
  676. Q_snprintf( material, sizeof(material),
  677. "materials/console/%s.vtf", szBackgroundName );
  678. }
  679. // load in the background vtf
  680. buf.Clear();
  681. m_pBackgroundTexture = LoadVTF( buf, material );
  682. if ( !m_pBackgroundTexture )
  683. {
  684. // fallback to opening just the default background
  685. m_pBackgroundTexture = LoadVTF( buf, ( aspectRatio >= 1.6f ) ? "materials/console/background01_widescreen.vtf" : "materials/console/background01.vtf" );
  686. if ( !m_pBackgroundTexture )
  687. {
  688. Error( "Can't find background image '%s'\n", material );
  689. return;
  690. }
  691. }
  692. // loading.vtf
  693. buf.Clear(); // added this Clear() because we saw cases where LoadVTF was not emptying the buf fully in the above section
  694. m_pLoadingTexture = LoadVTF( buf, "materials/console/startup_loading.vtf" );
  695. if ( !m_pLoadingTexture )
  696. {
  697. Error( "Can't find background image materials/console/startup_loading.vtf\n" );
  698. return;
  699. }
  700. }
  701. //-----------------------------------------------------------------------------
  702. // Purpose: Renders the startup video into the HWND
  703. //-----------------------------------------------------------------------------
  704. void CVideoMode_Common::DrawStartupVideo()
  705. {
  706. if ( IsX360() )
  707. return;
  708. CETWScope timer( "CVideoMode_Common::DrawStartupGraphic" );
  709. // render an avi, if we have one
  710. if ( !m_bPlayedStartupVideo && !InEditMode() && !ShouldForceVRActive() )
  711. {
  712. game->PlayStartupVideos();
  713. m_bPlayedStartupVideo = true;
  714. }
  715. }
  716. //-----------------------------------------------------------------------------
  717. // Purpose: Renders the startup graphic into the HWND
  718. //-----------------------------------------------------------------------------
  719. void CVideoMode_Common::DrawStartupGraphic()
  720. {
  721. if ( IsX360() )
  722. return;
  723. char debugstartup = CommandLine()->FindParm("-debugstartupscreen");
  724. SetupStartupGraphic();
  725. if ( !m_pBackgroundTexture || !m_pLoadingTexture )
  726. return;
  727. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  728. char pStartupGraphicName[MAX_PATH];
  729. ComputeStartupGraphicName( pStartupGraphicName, sizeof(pStartupGraphicName) );
  730. if(debugstartup)
  731. {
  732. // slam the startup graphic name for sanity - take your pick
  733. strcpy( pStartupGraphicName, "materials/console/background01.vtf");
  734. //strcpy( pStartupGraphicName, "materials/console/testramp.vtf");
  735. }
  736. // Allocate a white material
  737. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  738. pVMTKeyValues->SetString( "$basetexture", pStartupGraphicName + 10 );
  739. pVMTKeyValues->SetInt( "$ignorez", 1 );
  740. pVMTKeyValues->SetInt( "$nofog", 1 );
  741. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  742. pVMTKeyValues->SetInt( "$nocull", 1 );
  743. IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( "__background", pVMTKeyValues );
  744. pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  745. pVMTKeyValues->SetString( "$basetexture", "Console/startup_loading.vtf" );
  746. pVMTKeyValues->SetInt( "$translucent", 1 );
  747. pVMTKeyValues->SetInt( "$ignorez", 1 );
  748. pVMTKeyValues->SetInt( "$nofog", 1 );
  749. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  750. pVMTKeyValues->SetInt( "$nocull", 1 );
  751. IMaterial *pLoadingMaterial = g_pMaterialSystem->CreateMaterial( "__loading", pVMTKeyValues );
  752. int w = GetModeStereoWidth();
  753. int h = GetModeStereoHeight();
  754. int tw = m_pBackgroundTexture->Width();
  755. int th = m_pBackgroundTexture->Height();
  756. int lw = m_pLoadingTexture->Width();
  757. int lh = m_pLoadingTexture->Height();
  758. if (debugstartup)
  759. {
  760. for ( int repeat = 0; repeat<100000; repeat++)
  761. {
  762. pRenderContext->Viewport( 0, 0, w, h );
  763. pRenderContext->DepthRange( 0, 1 );
  764. pRenderContext->ClearColor3ub( 0, (repeat & 0x7) << 3, 0 );
  765. pRenderContext->ClearBuffers( true, true, true );
  766. pRenderContext->SetToneMappingScaleLinear( Vector(1,1,1) );
  767. if(1) // draw normal BK
  768. {
  769. float depth = 0.55f;
  770. int slide = (repeat) % 200; // 100 down and 100 up
  771. if (slide > 100)
  772. {
  773. slide = 200-slide; // aka 100-(slide-100).
  774. }
  775. // stop sliding about
  776. slide = 0;
  777. DrawScreenSpaceRectangle( pMaterial, 0, 0+slide, w, h-50, 0, 0, tw-1, th-1, tw, th, NULL,1,1,depth );
  778. DrawScreenSpaceRectangle( pLoadingMaterial, w-lw, h-lh+slide/2, lw, lh, 0, 0, lw-1, lh-1, lw, lh, NULL,1,1,depth-0.1 );
  779. }
  780. if(0)
  781. {
  782. // draw a grid too
  783. int grid_size = 8;
  784. float depthacc = 0.0;
  785. float depthinc = 1.0 / (float)((grid_size * grid_size)+1);
  786. for( int x = 0; x<grid_size; x++)
  787. {
  788. float cornerx = ((float)x) * 20.0f;
  789. for( int y=0; y<grid_size; y++)
  790. {
  791. float cornery = ((float)y) * 20.0f;
  792. //if (! ((x^y) & 1) )
  793. {
  794. DrawScreenSpaceRectangle( pMaterial, 10.0f+cornerx,10.0f+ cornery, 15, 15, 0, 0, tw-1, th-1, tw, th, NULL,1,1, depthacc );
  795. }
  796. depthacc += depthinc;
  797. }
  798. }
  799. }
  800. g_pMaterialSystem->SwapBuffers();
  801. }
  802. }
  803. else
  804. {
  805. pRenderContext->Viewport( 0, 0, w, h );
  806. pRenderContext->DepthRange( 0, 1 );
  807. pRenderContext->SetToneMappingScaleLinear( Vector(1,1,1) );
  808. float depth = 0.5f;
  809. // Make sure we clear both front & back buffer.
  810. for (int i = 0; i < 2; ++i)
  811. {
  812. pRenderContext->ClearColor3ub( 0, 0, 0 );
  813. pRenderContext->ClearBuffers( true, true, true );
  814. DrawScreenSpaceRectangle( pMaterial, 0, 0, w, h, 0, 0, tw-1, th-1, tw, th, NULL,1,1,depth );
  815. DrawScreenSpaceRectangle( pLoadingMaterial, w-lw, h-lh, lw, lh, 0, 0, lw-1, lh-1, lw, lh, NULL,1,1,depth );
  816. g_pMaterialSystem->SwapBuffers();
  817. }
  818. }
  819. #ifdef DX_TO_GL_ABSTRACTION
  820. g_pMaterialSystem->DoStartupShaderPreloading();
  821. #endif
  822. pMaterial->Release();
  823. pLoadingMaterial->Release();
  824. // release graphics
  825. DestroyVTFTexture( m_pBackgroundTexture );
  826. m_pBackgroundTexture = NULL;
  827. DestroyVTFTexture( m_pLoadingTexture );
  828. m_pLoadingTexture = NULL;
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose: Blits an image to the loading window hdc
  832. //-----------------------------------------------------------------------------
  833. void CVideoMode_Common::BlitGraphicToHDCWithAlpha(HDC hdc, byte *rgba, int imageWidth, int imageHeight, int x0, int y0, int x1, int y1)
  834. {
  835. #ifdef WIN32
  836. if ( IsX360() )
  837. return;
  838. int x = x0;
  839. int y = y0;
  840. int wide = x1 - x0;
  841. int tall = y1 - y0;
  842. Assert(imageWidth == wide && imageHeight == tall);
  843. int texwby4 = imageWidth << 2;
  844. for ( int v = 0; v < tall; v++ )
  845. {
  846. int *src = (int *)(rgba + (v * texwby4));
  847. int xaccum = 0;
  848. for ( int u = 0; u < wide; u++ )
  849. {
  850. byte *xsrc = (byte *)(src + xaccum);
  851. if (xsrc[3])
  852. {
  853. ::SetPixel(hdc, x + u, y + v, RGB(xsrc[0], xsrc[1], xsrc[2]));
  854. }
  855. xaccum += 1;
  856. }
  857. }
  858. #else
  859. Assert( !"Impl me" );
  860. #endif
  861. }
  862. void CVideoMode_Common::InvalidateWindow()
  863. {
  864. if ( CommandLine()->FindParm( "-noshaderapi" ) )
  865. {
  866. #if defined( USE_SDL )
  867. SDL_Event fake;
  868. memset(&fake, '\0', sizeof (SDL_Event));
  869. fake.type = SDL_WINDOWEVENT;
  870. fake.window.windowID = SDL_GetWindowID( (SDL_Window *) g_pLauncherMgr->GetWindowRef() );
  871. fake.window.event = SDL_WINDOWEVENT_EXPOSED;
  872. SDL_PushEvent(&fake);
  873. #else
  874. InvalidateRect( (HWND)game->GetMainWindow(), NULL, FALSE );
  875. #endif
  876. }
  877. }
  878. void CVideoMode_Common::DrawNullBackground( void *hHDC, int w, int h )
  879. {
  880. #ifdef WIN32
  881. if ( IsX360() )
  882. return;
  883. HDC hdc = (HDC)hHDC;
  884. // Show a message if running without renderer..
  885. if ( CommandLine()->FindParm( "-noshaderapi" ) )
  886. {
  887. HFONT fnt = CreateFontA( -18,
  888. 0,
  889. 0,
  890. 0,
  891. FW_NORMAL,
  892. FALSE,
  893. FALSE,
  894. FALSE,
  895. ANSI_CHARSET,
  896. OUT_TT_PRECIS,
  897. CLIP_DEFAULT_PRECIS,
  898. ANTIALIASED_QUALITY,
  899. DEFAULT_PITCH,
  900. "Arial" );
  901. HFONT oldFont = (HFONT)SelectObject( hdc, fnt );
  902. int oldBkMode = SetBkMode( hdc, TRANSPARENT );
  903. COLORREF oldFgColor = SetTextColor( hdc, RGB( 255, 255, 255 ) );
  904. HBRUSH br = CreateSolidBrush( RGB( 0, 0, 0 ) );
  905. HBRUSH oldBr = (HBRUSH)SelectObject( hdc, br );
  906. Rectangle( hdc, 0, 0, w, h );
  907. RECT rc;
  908. rc.left = 0;
  909. rc.top = 0;
  910. rc.right = w;
  911. rc.bottom = h;
  912. DrawText( hdc, "Running with -noshaderapi", -1, &rc, DT_NOPREFIX | DT_VCENTER | DT_CENTER | DT_SINGLELINE );
  913. rc.top = rc.bottom - 30;
  914. if ( host_state.worldmodel != NULL )
  915. {
  916. rc.left += 10;
  917. DrawText( hdc, modelloader->GetName( host_state.worldmodel ), -1, &rc, DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE );
  918. }
  919. SetTextColor( hdc, oldFgColor );
  920. SelectObject( hdc, oldBr );
  921. SetBkMode( hdc, oldBkMode );
  922. SelectObject( hdc, oldFont );
  923. DeleteObject( br );
  924. DeleteObject( fnt );
  925. }
  926. #else
  927. Assert( !"Impl me" );
  928. #endif
  929. }
  930. #ifndef _WIN32
  931. typedef unsigned char BYTE;
  932. typedef signed long LONG;
  933. typedef unsigned long ULONG;
  934. typedef char * LPSTR;
  935. typedef struct tagBITMAPINFOHEADER{
  936. DWORD biSize;
  937. LONG biWidth;
  938. LONG biHeight;
  939. WORD biPlanes;
  940. WORD biBitCount;
  941. DWORD biCompression;
  942. DWORD biSizeImage;
  943. LONG biXPelsPerMeter;
  944. LONG biYPelsPerMeter;
  945. DWORD biClrUsed;
  946. DWORD biClrImportant;
  947. } BITMAPINFOHEADER;
  948. typedef struct tagBITMAPFILEHEADER {
  949. WORD bfType;
  950. DWORD bfSize;
  951. WORD bfReserved1;
  952. WORD bfReserved2;
  953. DWORD bfOffBits;
  954. } BITMAPFILEHEADER;
  955. typedef struct tagRGBQUAD {
  956. BYTE rgbBlue;
  957. BYTE rgbGreen;
  958. BYTE rgbRed;
  959. BYTE rgbReserved;
  960. } RGBQUAD;
  961. /* constants for the biCompression field */
  962. #define BI_RGB 0L
  963. #define BI_RLE8 1L
  964. #define BI_RLE4 2L
  965. #define BI_BITFIELDS 3L
  966. #if 0
  967. typedef struct _GUID
  968. {
  969. unsigned long Data1;
  970. unsigned short Data2;
  971. unsigned short Data3;
  972. unsigned char Data4[8];
  973. } GUID;
  974. #endif
  975. typedef GUID UUID;
  976. #endif //WIN32
  977. //-----------------------------------------------------------------------------
  978. // Purpose: Blits an image to the loading window hdc
  979. //-----------------------------------------------------------------------------
  980. void CVideoMode_Common::BlitGraphicToHDC(HDC hdc, byte *rgba, int imageWidth, int imageHeight, int x0, int y0, int x1, int y1)
  981. {
  982. if ( IsX360() )
  983. return;
  984. #ifdef WIN32
  985. int x = x0;
  986. int y = y0;
  987. int wide = x1 - x0;
  988. int tall = y1 - y0;
  989. // Needs to be a multiple of 4
  990. int dibwide = ( wide + 3 ) & ~3;
  991. Assert(rgba);
  992. int texwby4 = imageWidth << 2;
  993. double st = Plat_FloatTime();
  994. void *destBits = NULL;
  995. HBITMAP bm;
  996. BITMAPINFO bmi;
  997. Q_memset( &bmi, 0, sizeof( bmi ) );
  998. BITMAPINFOHEADER *hdr = &bmi.bmiHeader;
  999. hdr->biSize = sizeof( *hdr );
  1000. hdr->biWidth = dibwide;
  1001. hdr->biHeight = -tall; // top down bitmap
  1002. hdr->biBitCount = 24;
  1003. hdr->biPlanes = 1;
  1004. hdr->biCompression = BI_RGB;
  1005. hdr->biSizeImage = dibwide * tall * 3;
  1006. hdr->biXPelsPerMeter = 3780;
  1007. hdr->biYPelsPerMeter = 3780;
  1008. // Create a "source" DC
  1009. HDC tempDC = CreateCompatibleDC( hdc );
  1010. // Create the dibsection bitmap
  1011. bm = CreateDIBSection
  1012. (
  1013. tempDC, // handle to DC
  1014. &bmi, // bitmap data
  1015. DIB_RGB_COLORS, // data type indicator
  1016. &destBits, // bit values
  1017. NULL, // handle to file mapping object
  1018. 0 // offset to bitmap bit values
  1019. );
  1020. // Select it into the source DC
  1021. HBITMAP oldBitmap = (HBITMAP)SelectObject( tempDC, bm );
  1022. // Setup for bilinaer filtering. If we don't do this filter here, there will be a big
  1023. // annoying pop when it switches to the vguimatsurface version of the background.
  1024. // We leave room for 14 bits of integer precision, so the image can be up to 16k x 16k.
  1025. const int BILINEAR_FIX_SHIFT = 17;
  1026. const int BILINEAR_FIX_MUL = (1 << BILINEAR_FIX_SHIFT);
  1027. #define FIXED_BLEND( a, b, out, frac ) \
  1028. out[0] = (a[0]*frac + b[0]*(BILINEAR_FIX_MUL-frac)) >> BILINEAR_FIX_SHIFT; \
  1029. out[1] = (a[1]*frac + b[1]*(BILINEAR_FIX_MUL-frac)) >> BILINEAR_FIX_SHIFT; \
  1030. out[2] = (a[2]*frac + b[2]*(BILINEAR_FIX_MUL-frac)) >> BILINEAR_FIX_SHIFT;
  1031. float eps = 0.001f;
  1032. float uMax = imageWidth - 1 - eps;
  1033. float vMax = imageHeight - 1 - eps;
  1034. int fixedBilinearV = 0;
  1035. int bilinearUInc = (int)( (uMax / (dibwide-1)) * BILINEAR_FIX_MUL );
  1036. int bilinearVInc = (int)( (vMax / (tall-1)) * BILINEAR_FIX_MUL );
  1037. for ( int v = 0; v < tall; v++ )
  1038. {
  1039. int iBilinearV = fixedBilinearV >> BILINEAR_FIX_SHIFT;
  1040. int fixedFractionV = fixedBilinearV & (BILINEAR_FIX_MUL-1);
  1041. fixedBilinearV += bilinearVInc;
  1042. int fixedBilinearU = 0;
  1043. byte *dest = (byte *)destBits + ( ( y + v ) * dibwide + x ) * 3;
  1044. for ( int u = 0; u < dibwide; u++, dest+=3 )
  1045. {
  1046. int iBilinearU = fixedBilinearU >> BILINEAR_FIX_SHIFT;
  1047. int fixedFractionU = fixedBilinearU & (BILINEAR_FIX_MUL-1);
  1048. fixedBilinearU += bilinearUInc;
  1049. Assert( iBilinearU >= 0 && iBilinearU+1 < imageWidth );
  1050. Assert( iBilinearV >= 0 && iBilinearV+1 < imageHeight );
  1051. byte *srcTopLine = rgba + iBilinearV * texwby4;
  1052. byte *srcBottomLine = rgba + (iBilinearV+1) * texwby4;
  1053. byte *xsrc[4] = {
  1054. srcTopLine + (iBilinearU+0)*4, srcTopLine + (iBilinearU+1)*4,
  1055. srcBottomLine + (iBilinearU+0)*4, srcBottomLine + (iBilinearU+1)*4 };
  1056. int topColor[3], bottomColor[3], finalColor[3];
  1057. FIXED_BLEND( xsrc[1], xsrc[0], topColor, fixedFractionU );
  1058. FIXED_BLEND( xsrc[3], xsrc[2], bottomColor, fixedFractionU );
  1059. FIXED_BLEND( bottomColor, topColor, finalColor, fixedFractionV );
  1060. // Windows wants the colors in reverse order.
  1061. dest[0] = finalColor[2];
  1062. dest[1] = finalColor[1];
  1063. dest[2] = finalColor[0];
  1064. }
  1065. }
  1066. // Now do the Blt
  1067. BitBlt( hdc, 0, 0, dibwide, tall, tempDC, 0, 0, SRCCOPY );
  1068. // This only draws if running -noshaderapi
  1069. DrawNullBackground( hdc, dibwide, tall );
  1070. // Restore the old Bitmap
  1071. SelectObject( tempDC, oldBitmap );
  1072. // Destroy the temporary DC
  1073. DeleteDC( tempDC );
  1074. // Destroy the DIBSection bitmap
  1075. DeleteObject( bm );
  1076. double elapsed = Plat_FloatTime() - st;
  1077. COM_TimestampedLog( "BlitGraphicToHDC: new ver took %.4f", elapsed );
  1078. #else
  1079. Assert( !"Impl me" );
  1080. #endif
  1081. }
  1082. //-----------------------------------------------------------------------------
  1083. // Purpose: This is called in response to a WM_MOVE message
  1084. //-----------------------------------------------------------------------------
  1085. void CVideoMode_Common::UpdateWindowPosition( void )
  1086. {
  1087. int x, y, w, h;
  1088. // Get the window from the game ( right place for it? )
  1089. game->GetWindowRect( &x, &y, &w, &h );
  1090. #ifdef WIN32
  1091. RECT window_rect;
  1092. window_rect.left = x;
  1093. window_rect.right = x + w;
  1094. window_rect.top = y;
  1095. window_rect.bottom = y + h;
  1096. #endif
  1097. // NOTE: We need to feed this back into the video mode stuff
  1098. // esp. in Resizing window mode.
  1099. }
  1100. void CVideoMode_Common::ChangeDisplaySettingsToFullscreen( int nWidth, int nHeight, int nBPP )
  1101. {
  1102. }
  1103. void CVideoMode_Common::ReleaseFullScreen( void )
  1104. {
  1105. }
  1106. //-----------------------------------------------------------------------------
  1107. // Purpose: Returns the optimal refresh rate for the specified mode
  1108. //-----------------------------------------------------------------------------
  1109. int CVideoMode_Common::GetRefreshRateForMode( const vmode_t *pMode )
  1110. {
  1111. int nRefreshRate = pMode->refreshRate;
  1112. // FIXME: We should only read this once, at the beginning
  1113. // override the refresh rate from the command-line maybe
  1114. nRefreshRate = CommandLine()->ParmValue( "-freq", nRefreshRate );
  1115. nRefreshRate = CommandLine()->ParmValue( "-refresh", nRefreshRate );
  1116. nRefreshRate = CommandLine()->ParmValue( "-refreshrate", nRefreshRate );
  1117. return nRefreshRate;
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose:
  1121. // Input : *mode -
  1122. // Output : Returns true on success, false on failure.
  1123. //-----------------------------------------------------------------------------
  1124. void CVideoMode_Common::AdjustWindow( int nWidth, int nHeight, int nBPP, bool bWindowed )
  1125. {
  1126. if ( g_bTextMode )
  1127. return;
  1128. // Use Change Display Settings to go full screen
  1129. ChangeDisplaySettingsToFullscreen( nWidth, nHeight, nBPP );
  1130. RECT WindowRect;
  1131. WindowRect.top = 0;
  1132. WindowRect.left = 0;
  1133. WindowRect.right = nWidth;
  1134. WindowRect.bottom = nHeight;
  1135. #ifndef USE_SDL
  1136. #ifndef _X360
  1137. // Get window style
  1138. DWORD style = GetWindowLong( (HWND)game->GetMainWindow(), GWL_STYLE );
  1139. DWORD exStyle = GetWindowLong( (HWND)game->GetMainWindow(), GWL_EXSTYLE );
  1140. if ( bWindowed )
  1141. {
  1142. // Give it a frame (pretty much WS_OVERLAPPEDWINDOW except for we do not modify the
  1143. // flags corresponding to resizing-frame and maximize-box)
  1144. if( !CommandLine()->FindParm( "-noborder" ) && !m_bVROverride )
  1145. {
  1146. style |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
  1147. }
  1148. else
  1149. {
  1150. style &= ~WS_OVERLAPPEDWINDOW;
  1151. }
  1152. // remove topmost flag
  1153. exStyle &= ~WS_EX_TOPMOST;
  1154. SetWindowLong( (HWND)game->GetMainWindow(), GWL_EXSTYLE, exStyle );
  1155. }
  1156. else
  1157. {
  1158. // Remove window border going into fullscreen mode to avoid Vista sizing issues when DWM is enabled
  1159. style &= ~WS_OVERLAPPEDWINDOW;
  1160. }
  1161. SetWindowLong( (HWND)game->GetMainWindow(), GWL_STYLE, style );
  1162. // Compute rect needed for that size client area based on window style
  1163. AdjustWindowRectEx( &WindowRect, style, FALSE, exStyle );
  1164. #endif
  1165. // Prepare to set window pos, which is required when toggling between topmost and not window flags
  1166. HWND hWndAfter = NULL;
  1167. DWORD dwSwpFlags = 0;
  1168. #ifndef _X360
  1169. {
  1170. if ( bWindowed )
  1171. {
  1172. hWndAfter = HWND_NOTOPMOST;
  1173. }
  1174. else
  1175. {
  1176. hWndAfter = HWND_TOPMOST;
  1177. }
  1178. dwSwpFlags = SWP_FRAMECHANGED;
  1179. }
  1180. #else
  1181. {
  1182. dwSwpFlags = SWP_NOZORDER;
  1183. }
  1184. #endif
  1185. // Move the window to 0, 0 and the new true size
  1186. SetWindowPos( (HWND)game->GetMainWindow(),
  1187. hWndAfter,
  1188. 0, 0, WindowRect.right - WindowRect.left,
  1189. WindowRect.bottom - WindowRect.top,
  1190. SWP_NOREDRAW | dwSwpFlags );
  1191. #endif // !USE_SDL
  1192. // Now center
  1193. CenterEngineWindow( game->GetMainWindow(),
  1194. WindowRect.right - WindowRect.left,
  1195. WindowRect.bottom - WindowRect.top );
  1196. #if defined( USE_SDL )
  1197. g_pLauncherMgr->SetWindowFullScreen( !bWindowed, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top );
  1198. CenterEngineWindow( game->GetMainWindow(),
  1199. WindowRect.right - WindowRect.left,
  1200. WindowRect.bottom - WindowRect.top );
  1201. g_pLauncherMgr->SizeWindow( WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top );
  1202. if( bWindowed )
  1203. {
  1204. SDL_Window* win = (SDL_Window*)g_pLauncherMgr->GetWindowRef();
  1205. if ( m_bVROverride || CommandLine()->FindParm( "-noborder" ) )
  1206. SDL_SetWindowBordered( win, SDL_FALSE );
  1207. else
  1208. SDL_SetWindowBordered( win, SDL_TRUE );
  1209. }
  1210. #endif
  1211. game->SetWindowSize( nWidth, nHeight );
  1212. // Make sure we have updated window information
  1213. UpdateWindowPosition();
  1214. MarkClientViewRectDirty();
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. // Purpose:
  1218. //-----------------------------------------------------------------------------
  1219. void CVideoMode_Common::Shutdown( void )
  1220. {
  1221. ReleaseFullScreen();
  1222. game->DestroyGameWindow();
  1223. if ( !GetInitialized() )
  1224. return;
  1225. SetInitialized( false );
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Gets/sets the client view rectangle
  1229. //-----------------------------------------------------------------------------
  1230. const vrect_t &CVideoMode_Common::GetClientViewRect( ) const
  1231. {
  1232. const_cast<CVideoMode_Common*>(this)->RecomputeClientViewRect();
  1233. return m_ClientViewRect;
  1234. }
  1235. void CVideoMode_Common::SetClientViewRect( const vrect_t &viewRect )
  1236. {
  1237. m_ClientViewRect = viewRect;
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Marks the client view rect dirty
  1241. //-----------------------------------------------------------------------------
  1242. void CVideoMode_Common::MarkClientViewRectDirty()
  1243. {
  1244. m_bClientViewRectDirty = true;
  1245. }
  1246. void CVideoMode_Common::RecomputeClientViewRect()
  1247. {
  1248. if ( !InEditMode() )
  1249. {
  1250. if ( !m_bClientViewRectDirty )
  1251. return;
  1252. }
  1253. m_bClientViewRectDirty = false;
  1254. int nWidth, nHeight;
  1255. CMatRenderContextPtr pRenderContext( materials );
  1256. pRenderContext->GetRenderTargetDimensions( nWidth, nHeight );
  1257. m_ClientViewRect.width = nWidth;
  1258. m_ClientViewRect.height = nHeight;
  1259. m_ClientViewRect.x = 0;
  1260. m_ClientViewRect.y = 0;
  1261. if (!nWidth || !nHeight)
  1262. {
  1263. // didn't successfully get the screen size, try again next frame
  1264. // window is probably minimized
  1265. m_bClientViewRectDirty = true;
  1266. }
  1267. }
  1268. //-----------------------------------------------------------------------------
  1269. // Purpose:
  1270. // Input : hWndCenter -
  1271. // width -
  1272. // height -
  1273. // Output : static void
  1274. //-----------------------------------------------------------------------------
  1275. void CVideoMode_Common::CenterEngineWindow( void *hWndCenter, int width, int height)
  1276. {
  1277. int CenterX, CenterY;
  1278. #if defined(USE_SDL)
  1279. // Get the displayindex, and center our window on that display.
  1280. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  1281. int displayindex = sdl_displayindex.IsValid() ? sdl_displayindex.GetInt() : 0;
  1282. SDL_DisplayMode mode;
  1283. SDL_GetCurrentDisplayMode( displayindex, &mode );
  1284. const int wide = mode.w;
  1285. const int tall = mode.h;
  1286. CenterX = (wide - width) / 2;
  1287. CenterY = (tall - height) / 2;
  1288. CenterX = (CenterX < 0) ? 0: CenterX;
  1289. CenterY = (CenterY < 0) ? 0: CenterY;
  1290. // tweak the x and w positions if the user species them on the command-line
  1291. CenterX = CommandLine()->ParmValue( "-x", CenterX );
  1292. CenterY = CommandLine()->ParmValue( "-y", CenterY );
  1293. // also check for the negated form (since it is hard to say "-x -1000")
  1294. int negx = CommandLine()->ParmValue( "-negx", 0 );
  1295. if (negx > 0)
  1296. {
  1297. CenterX = -negx;
  1298. }
  1299. int negy = CommandLine()->ParmValue( "-negy", 0 );
  1300. if (negy > 0)
  1301. {
  1302. CenterY = -negy;
  1303. }
  1304. SDL_Rect rect = { 0, 0, 0, 0 };
  1305. SDL_GetDisplayBounds( displayindex, &rect );
  1306. CenterX += rect.x;
  1307. CenterY += rect.y;
  1308. game->SetWindowXY( CenterX, CenterY );
  1309. g_pLauncherMgr->MoveWindow( CenterX, CenterY );
  1310. #else
  1311. if ( IsPC() )
  1312. {
  1313. // In windowed mode go through game->GetDesktopInfo because system metrics change
  1314. // when going fullscreen vs windowed.
  1315. // Use system metrics for fullscreen or when game didn't have a chance to initialize.
  1316. int cxScreen = 0, cyScreen = 0, refreshRate = 0;
  1317. if ( !( WS_EX_TOPMOST & ::GetWindowLong( (HWND)hWndCenter, GWL_EXSTYLE ) ) && m_bWindowed )
  1318. {
  1319. game->GetDesktopInfo( cxScreen, cyScreen, refreshRate );
  1320. }
  1321. if ( !cxScreen || !cyScreen )
  1322. {
  1323. cxScreen = GetSystemMetrics(SM_CXSCREEN);
  1324. cyScreen = GetSystemMetrics(SM_CYSCREEN);
  1325. }
  1326. // Compute top-left corner offset
  1327. CenterX = (cxScreen - width) / 2;
  1328. CenterY = (cyScreen - height) / 2;
  1329. CenterX = (CenterX < 0) ? 0: CenterX;
  1330. CenterY = (CenterY < 0) ? 0: CenterY;
  1331. }
  1332. else
  1333. {
  1334. CenterX = 0;
  1335. CenterY = 0;
  1336. }
  1337. if( m_bVROverride )
  1338. {
  1339. CenterX = m_nVROverrideX;
  1340. CenterY = m_nVROverrideY;
  1341. }
  1342. // tweak the x and w positions if the user species them on the command-line
  1343. CenterX = CommandLine()->ParmValue( "-x", CenterX );
  1344. CenterY = CommandLine()->ParmValue( "-y", CenterY );
  1345. game->SetWindowXY( CenterX, CenterY );
  1346. SetWindowPos ( (HWND)hWndCenter, NULL, CenterX, CenterY, 0, 0,
  1347. SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  1348. #endif
  1349. }
  1350. //-----------------------------------------------------------------------------
  1351. // Handle alt-tab
  1352. //-----------------------------------------------------------------------------
  1353. void CVideoMode_Common::RestoreVideo( void )
  1354. {
  1355. }
  1356. void CVideoMode_Common::ReleaseVideo( void )
  1357. {
  1358. }
  1359. //-----------------------------------------------------------------------------
  1360. // Read screen pixels
  1361. //-----------------------------------------------------------------------------
  1362. void CVideoMode_Common::ReadScreenPixels( int x, int y, int w, int h, void *pBuffer, ImageFormat format )
  1363. {
  1364. int nBytes = ImageLoader::GetMemRequired( w, h, 1, format, false );
  1365. memset( pBuffer, 0, nBytes );
  1366. }
  1367. //-----------------------------------------------------------------------------
  1368. // Purpose: Write vid.buffer out as a .tga file
  1369. //-----------------------------------------------------------------------------
  1370. void CVideoMode_Common::TakeSnapshotTGA( const char *pFilename )
  1371. {
  1372. // bitmap bits
  1373. uint8 *pImage = new uint8[ GetModeStereoWidth() * 3 * GetModeStereoHeight() ];
  1374. // Get Bits from the material system
  1375. ReadScreenPixels( 0, 0, GetModeStereoWidth(), GetModeStereoHeight(), pImage, IMAGE_FORMAT_RGB888 );
  1376. CUtlBuffer outBuf;
  1377. if ( TGAWriter::WriteToBuffer( pImage, outBuf, GetModeStereoWidth(), GetModeStereoHeight(), IMAGE_FORMAT_RGB888,
  1378. IMAGE_FORMAT_RGB888 ) )
  1379. {
  1380. if ( !g_pFileSystem->WriteFile( pFilename, NULL, outBuf ) )
  1381. {
  1382. Warning( "Couldn't write bitmap data snapshot to file %s.\n", pFilename );
  1383. }
  1384. else
  1385. {
  1386. char szPath[MAX_PATH];
  1387. szPath[0] = 0;
  1388. if ( g_pFileSystem->GetLocalPath( pFilename, szPath, sizeof(szPath) ) )
  1389. {
  1390. AddScreenshotToSteam( szPath, GetModeStereoWidth(), GetModeStereoHeight() );
  1391. }
  1392. }
  1393. }
  1394. delete[] pImage;
  1395. }
  1396. //-----------------------------------------------------------------------------
  1397. // PFM screenshot helpers
  1398. //-----------------------------------------------------------------------------
  1399. ITexture *CVideoMode_Common::GetBuildCubemaps16BitTexture( void )
  1400. {
  1401. return materials->FindTexture( "_rt_BuildCubemaps16bit", TEXTURE_GROUP_RENDER_TARGET );
  1402. }
  1403. ITexture *CVideoMode_Common::GetFullFrameFB0( void )
  1404. {
  1405. return materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  1406. }
  1407. void CVideoMode_Common::BlitHiLoScreenBuffersTo16Bit( void )
  1408. {
  1409. if ( IsX360() )
  1410. {
  1411. // FIXME: this breaks in 480p due to (at least) the multisampled depth buffer (need to cache, clear and restore the depth target)
  1412. Assert( 0 );
  1413. return;
  1414. }
  1415. IMaterial *pHDRCombineMaterial = materials->FindMaterial( "dev/hdrcombineto16bit", TEXTURE_GROUP_OTHER, true );
  1416. // if( IsErrorMaterial( pHDRCombineMaterial ) )
  1417. // {
  1418. // Assert( 0 );
  1419. // return;
  1420. // }
  1421. CMatRenderContextPtr pRenderContext( materials );
  1422. ITexture *pSaveRenderTarget;
  1423. pSaveRenderTarget = pRenderContext->GetRenderTarget();
  1424. int oldX, oldY, oldW, oldH;
  1425. pRenderContext->GetViewport( oldX, oldY, oldW, oldH );
  1426. pRenderContext->SetRenderTarget( GetBuildCubemaps16BitTexture() );
  1427. int width, height;
  1428. pRenderContext->GetRenderTargetDimensions( width, height );
  1429. pRenderContext->Viewport( 0, 0, width, height );
  1430. pRenderContext->DrawScreenSpaceQuad( pHDRCombineMaterial );
  1431. pRenderContext->SetRenderTarget( pSaveRenderTarget );
  1432. pRenderContext->Viewport( oldX, oldY, oldW, oldH );
  1433. }
  1434. void GetCubemapOffset( CubeMapFaceIndex_t faceIndex, int &x, int &y, int &faceDim )
  1435. {
  1436. int fbWidth, fbHeight;
  1437. materials->GetBackBufferDimensions( fbWidth, fbHeight );
  1438. if( fbWidth * 4 > fbHeight * 3 )
  1439. {
  1440. faceDim = fbHeight / 3;
  1441. }
  1442. else
  1443. {
  1444. faceDim = fbWidth / 4;
  1445. }
  1446. switch( faceIndex )
  1447. {
  1448. case CUBEMAP_FACE_RIGHT:
  1449. x = 2;
  1450. y = 1;
  1451. break;
  1452. case CUBEMAP_FACE_LEFT:
  1453. x = 0;
  1454. y = 1;
  1455. break;
  1456. case CUBEMAP_FACE_BACK:
  1457. x = 1;
  1458. y = 1;
  1459. break;
  1460. case CUBEMAP_FACE_FRONT:
  1461. x = 3;
  1462. y = 1;
  1463. break;
  1464. case CUBEMAP_FACE_UP:
  1465. x = 2;
  1466. y = 0;
  1467. break;
  1468. case CUBEMAP_FACE_DOWN:
  1469. x = 2;
  1470. y = 2;
  1471. break;
  1472. NO_DEFAULT
  1473. }
  1474. x *= faceDim;
  1475. y *= faceDim;
  1476. }
  1477. //-----------------------------------------------------------------------------
  1478. // Takes a snapshot to PFM
  1479. //-----------------------------------------------------------------------------
  1480. void CVideoMode_Common::TakeSnapshotPFMRect( const char *pFilename, int x, int y, int w, int h, int resampleWidth, int resampleHeight, CubeMapFaceIndex_t faceIndex )
  1481. {
  1482. if ( IsX360() )
  1483. {
  1484. // FIXME: this breaks in 480p due to (at least) the multisampled depth buffer (need to cache, clear and restore the depth target)
  1485. Assert( 0 );
  1486. return;
  1487. }
  1488. if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE )
  1489. {
  1490. Warning( "Unable to take PFM screenshots if HDR isn't enabled!\n" );
  1491. return;
  1492. }
  1493. // hack
  1494. // resampleWidth = w;
  1495. // resampleHeight = h;
  1496. // bitmap bits
  1497. float16 *pImage = ( float16 * )malloc( w * h * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGBA16161616F ) );
  1498. float *pImage1 = ( float * )malloc( w * h * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGB323232F ) );
  1499. CMatRenderContextPtr pRenderContext( materials );
  1500. // Save the current render target.
  1501. ITexture *pSaveRenderTarget = pRenderContext->GetRenderTarget();
  1502. // Set this as the render target so that we can read it.
  1503. pRenderContext->SetRenderTarget( GetFullFrameFB0() );
  1504. // Get Bits from the material system
  1505. ReadScreenPixels( x, y, w, h, pImage, IMAGE_FORMAT_RGBA16161616F );
  1506. // Draw what we just grabbed to the screen
  1507. pRenderContext->SetRenderTarget( NULL);
  1508. int scrw, scrh;
  1509. pRenderContext->GetRenderTargetDimensions( scrw, scrh );
  1510. pRenderContext->Viewport( 0, 0, scrw,scrh );
  1511. int offsetX, offsetY, faceDim;
  1512. GetCubemapOffset( faceIndex, offsetX, offsetY, faceDim );
  1513. pRenderContext->DrawScreenSpaceRectangle( materials->FindMaterial( "dev/copyfullframefb", "" ),
  1514. offsetX, offsetY, faceDim, faceDim, 0, 0, w-1, h-1, scrw, scrh );
  1515. // Restore the render target.
  1516. pRenderContext->SetRenderTarget( pSaveRenderTarget );
  1517. // convert from float16 to float32
  1518. ImageLoader::ConvertImageFormat( ( unsigned char * )pImage, IMAGE_FORMAT_RGBA16161616F,
  1519. ( unsigned char * )pImage1, IMAGE_FORMAT_RGB323232F,
  1520. w, h );
  1521. Assert( w == h ); // garymcthack - this only works for square images
  1522. float *pFloatImage = ( float * )malloc( resampleWidth * resampleHeight * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGB323232F ) );
  1523. ImageLoader::ResampleInfo_t info;
  1524. info.m_pSrc = ( unsigned char * )pImage1;
  1525. info.m_pDest = ( unsigned char * )pFloatImage;
  1526. info.m_nSrcWidth = w;
  1527. info.m_nSrcHeight = h;
  1528. info.m_nDestWidth = resampleWidth;
  1529. info.m_nDestHeight = resampleHeight;
  1530. info.m_flSrcGamma = 1.0f;
  1531. info.m_flDestGamma = 1.0f;
  1532. if( !ImageLoader::ResampleRGB323232F( info ) )
  1533. {
  1534. Sys_Error( "Can't resample\n" );
  1535. }
  1536. PFMWrite( pFloatImage, pFilename, resampleWidth, resampleHeight );
  1537. free( pImage1 );
  1538. free( pImage );
  1539. free( pFloatImage );
  1540. }
  1541. //-----------------------------------------------------------------------------
  1542. // Takes a snapshot
  1543. //-----------------------------------------------------------------------------
  1544. void CVideoMode_Common::TakeSnapshotTGARect( const char *pFilename, int x, int y, int w, int h, int resampleWidth, int resampleHeight, bool bPFM, CubeMapFaceIndex_t faceIndex )
  1545. {
  1546. if ( IsX360() )
  1547. {
  1548. Assert( 0 );
  1549. return;
  1550. }
  1551. if ( bPFM )
  1552. {
  1553. TakeSnapshotPFMRect( pFilename, x, y, w, h, resampleWidth, resampleHeight, faceIndex );
  1554. return;
  1555. }
  1556. // bitmap bits
  1557. uint8 *pImage = new uint8[ w * h * 4 ];
  1558. uint8 *pImage1 = new uint8[ resampleWidth * resampleHeight * 4 ];
  1559. // Get Bits from the material system
  1560. ReadScreenPixels( x, y, w, h, pImage, IMAGE_FORMAT_RGBA8888 );
  1561. Assert( w == h ); // garymcthack - this only works for square images
  1562. ImageLoader::ResampleInfo_t info;
  1563. info.m_pSrc = pImage;
  1564. info.m_pDest = pImage1;
  1565. info.m_nSrcWidth = w;
  1566. info.m_nSrcHeight = h;
  1567. info.m_nDestWidth = resampleWidth;
  1568. info.m_nDestHeight = resampleHeight;
  1569. info.m_flSrcGamma = 1.0f;
  1570. info.m_flDestGamma = 1.0f;
  1571. if( !ImageLoader::ResampleRGBA8888( info ) )
  1572. {
  1573. Sys_Error( "Can't resample\n" );
  1574. }
  1575. CUtlBuffer outBuf;
  1576. if ( TGAWriter::WriteToBuffer( pImage1, outBuf, resampleWidth, resampleHeight, IMAGE_FORMAT_RGBA8888, IMAGE_FORMAT_RGBA8888 ) )
  1577. {
  1578. if ( !g_pFileSystem->WriteFile( pFilename, NULL, outBuf ) )
  1579. {
  1580. Error( "Couldn't write bitmap data snapshot to file %s.\n", pFilename );
  1581. }
  1582. else
  1583. {
  1584. DevMsg( "Screenshot: %dx%d saved to '%s'.\n", w, h, pFilename );
  1585. }
  1586. }
  1587. delete[] pImage1;
  1588. delete[] pImage;
  1589. materials->SwapBuffers();
  1590. }
  1591. //-----------------------------------------------------------------------------
  1592. // Purpose: Writes the data in *data to the sequentially number .bmp file filename
  1593. // Input : *filename -
  1594. // width -
  1595. // height -
  1596. // depth -
  1597. // *data -
  1598. // Output : static void
  1599. //-----------------------------------------------------------------------------
  1600. static void VID_ProcessMovieFrame( const MovieInfo_t& info, bool jpeg, const char *filename, int width, int height, byte *data )
  1601. {
  1602. CUtlBuffer outBuf;
  1603. bool bSuccess = false;
  1604. if ( jpeg )
  1605. {
  1606. bSuccess = videomode->TakeSnapshotJPEGToBuffer( outBuf, info.jpeg_quality );
  1607. }
  1608. else
  1609. {
  1610. bSuccess = TGAWriter::WriteToBuffer( data, outBuf, width, height, IMAGE_FORMAT_BGR888, IMAGE_FORMAT_RGB888 );
  1611. }
  1612. if ( bSuccess )
  1613. {
  1614. if ( !g_pFileSystem->WriteFile( filename, NULL, outBuf ) )
  1615. {
  1616. Warning( "Couldn't write movie snapshot to file %s.\n", filename );
  1617. Cbuf_AddText( "endmovie\n" );
  1618. }
  1619. }
  1620. }
  1621. //-----------------------------------------------------------------------------
  1622. // Purpose: Store current frame to numbered .bmp file
  1623. // Input : *pFilename -
  1624. //-----------------------------------------------------------------------------
  1625. extern IVideoRecorder *g_pVideoRecorder;
  1626. void CVideoMode_Common::WriteMovieFrame( const MovieInfo_t& info )
  1627. {
  1628. char const *pMovieName = info.moviename;
  1629. int nMovieFrame = info.movieframe;
  1630. if ( g_LostVideoMemory )
  1631. return;
  1632. if ( !pMovieName[0] )
  1633. {
  1634. Cbuf_AddText( "endmovie\n" );
  1635. ConMsg( "Tried to write movie buffer with no filename set!\n" );
  1636. return;
  1637. }
  1638. int imagesize = GetModeStereoWidth() * GetModeStereoHeight();
  1639. BGR888_t *hp = new BGR888_t[ imagesize ];
  1640. if ( hp == NULL )
  1641. {
  1642. Sys_Error( "Couldn't allocate bitmap header to snapshot.\n" );
  1643. }
  1644. // Get Bits from material system
  1645. ReadScreenPixels( 0, 0, GetModeStereoWidth(), GetModeStereoHeight(), hp, IMAGE_FORMAT_BGR888 );
  1646. // Store frame to disk
  1647. if ( info.DoTga() )
  1648. {
  1649. VID_ProcessMovieFrame( info, false, va( "%s%04d.tga", pMovieName, nMovieFrame ),
  1650. GetModeStereoWidth(), GetModeStereoHeight(), (unsigned char*)hp );
  1651. }
  1652. if ( info.DoJpg() )
  1653. {
  1654. VID_ProcessMovieFrame( info, true, va( "%s%04d.jpg", pMovieName, nMovieFrame ),
  1655. GetModeStereoWidth(), GetModeStereoHeight(), (unsigned char*)hp );
  1656. }
  1657. if ( info.DoVideo() )
  1658. {
  1659. g_pVideoRecorder->AppendVideoFrame( hp );
  1660. }
  1661. delete[] hp;
  1662. }
  1663. //-----------------------------------------------------------------------------
  1664. // Purpose: Expanded data destination object for CUtlBuffer output
  1665. //-----------------------------------------------------------------------------
  1666. struct JPEGDestinationManager_t
  1667. {
  1668. struct jpeg_destination_mgr pub; // public fields
  1669. CUtlBuffer *pBuffer; // target/final buffer
  1670. byte *buffer; // start of temp buffer
  1671. };
  1672. // choose an efficiently bufferaable size
  1673. #define OUTPUT_BUF_SIZE 4096
  1674. //-----------------------------------------------------------------------------
  1675. // Purpose: Initialize destination --- called by jpeg_start_compress
  1676. // before any data is actually written.
  1677. //-----------------------------------------------------------------------------
  1678. METHODDEF(void) init_destination (j_compress_ptr cinfo)
  1679. {
  1680. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t *) cinfo->dest;
  1681. // Allocate the output buffer --- it will be released when done with image
  1682. dest->buffer = (byte *)
  1683. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  1684. OUTPUT_BUF_SIZE * sizeof(byte));
  1685. dest->pub.next_output_byte = dest->buffer;
  1686. dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  1687. }
  1688. //-----------------------------------------------------------------------------
  1689. // Purpose: Empty the output buffer --- called whenever buffer fills up.
  1690. // Input : boolean -
  1691. //-----------------------------------------------------------------------------
  1692. METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo)
  1693. {
  1694. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  1695. CUtlBuffer *buf = dest->pBuffer;
  1696. // Add some data
  1697. buf->Put( dest->buffer, OUTPUT_BUF_SIZE );
  1698. dest->pub.next_output_byte = dest->buffer;
  1699. dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  1700. return TRUE;
  1701. }
  1702. //-----------------------------------------------------------------------------
  1703. // Purpose: Terminate destination --- called by jpeg_finish_compress
  1704. // after all data has been written. Usually needs to flush buffer.
  1705. //
  1706. // NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
  1707. // application must deal with any cleanup that should happen even
  1708. // for error exit.
  1709. //-----------------------------------------------------------------------------
  1710. METHODDEF(void) term_destination (j_compress_ptr cinfo)
  1711. {
  1712. JPEGDestinationManager_t *dest = (JPEGDestinationManager_t *) cinfo->dest;
  1713. size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
  1714. CUtlBuffer *buf = dest->pBuffer;
  1715. /* Write any data remaining in the buffer */
  1716. if (datacount > 0)
  1717. {
  1718. buf->Put( dest->buffer, datacount );
  1719. }
  1720. }
  1721. //-----------------------------------------------------------------------------
  1722. // Purpose: Set up functions for writing data to a CUtlBuffer instead of FILE *
  1723. //-----------------------------------------------------------------------------
  1724. GLOBAL(void) jpeg_UtlBuffer_dest (j_compress_ptr cinfo, CUtlBuffer *pBuffer )
  1725. {
  1726. JPEGDestinationManager_t *dest;
  1727. /* The destination object is made permanent so that multiple JPEG images
  1728. * can be written to the same file without re-executing jpeg_stdio_dest.
  1729. * This makes it dangerous to use this manager and a different destination
  1730. * manager serially with the same JPEG object, because their private object
  1731. * sizes may be different. Caveat programmer.
  1732. */
  1733. if (cinfo->dest == NULL) { /* first time for this JPEG object? */
  1734. cinfo->dest = (struct jpeg_destination_mgr *)
  1735. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  1736. sizeof(JPEGDestinationManager_t));
  1737. }
  1738. dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  1739. dest->pub.init_destination = init_destination;
  1740. dest->pub.empty_output_buffer = empty_output_buffer;
  1741. dest->pub.term_destination = term_destination;
  1742. dest->pBuffer = pBuffer;
  1743. }
  1744. bool CVideoMode_Common::TakeSnapshotJPEGToBuffer( CUtlBuffer& buf, int quality )
  1745. {
  1746. #if !defined( _X360 )
  1747. if ( g_LostVideoMemory )
  1748. return false;
  1749. // Validate quality level
  1750. quality = clamp( quality, 1, 100 );
  1751. // Allocate space for bits
  1752. uint8 *pImage = new uint8[ GetModeStereoWidth() * 3 * GetModeStereoHeight() ];
  1753. if ( !pImage )
  1754. {
  1755. Msg( "Unable to allocate %i bytes for image\n", GetModeStereoWidth() * 3 * GetModeStereoHeight() );
  1756. return false;
  1757. }
  1758. // Get Bits from the material system
  1759. ReadScreenPixels( 0, 0, GetModeStereoWidth(), GetModeStereoHeight(), pImage, IMAGE_FORMAT_RGB888 );
  1760. JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
  1761. int row_stride; // physical row width in image buffer
  1762. // stderr handler
  1763. struct jpeg_error_mgr jerr;
  1764. // compression data structure
  1765. struct jpeg_compress_struct cinfo;
  1766. row_stride = GetModeStereoWidth() * 3; // JSAMPLEs per row in image_buffer
  1767. // point at stderr
  1768. cinfo.err = jpeg_std_error(&jerr);
  1769. // create compressor
  1770. jpeg_create_compress(&cinfo);
  1771. // Hook CUtlBuffer to compression
  1772. jpeg_UtlBuffer_dest(&cinfo, &buf );
  1773. // image width and height, in pixels
  1774. cinfo.image_width = GetModeStereoWidth();
  1775. cinfo.image_height = GetModeStereoHeight();
  1776. // RGB is 3 componnent
  1777. cinfo.input_components = 3;
  1778. // # of color components per pixel
  1779. cinfo.in_color_space = JCS_RGB;
  1780. // Apply settings
  1781. jpeg_set_defaults(&cinfo);
  1782. jpeg_set_quality(&cinfo, quality, TRUE );
  1783. // Start compressor
  1784. jpeg_start_compress(&cinfo, TRUE);
  1785. // Write scanlines
  1786. while ( cinfo.next_scanline < cinfo.image_height )
  1787. {
  1788. row_pointer[ 0 ] = &pImage[ cinfo.next_scanline * row_stride ];
  1789. jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  1790. }
  1791. // Finalize image
  1792. jpeg_finish_compress(&cinfo);
  1793. // Cleanup
  1794. jpeg_destroy_compress(&cinfo);
  1795. delete[] pImage;
  1796. #else
  1797. // not supporting
  1798. Assert( 0 );
  1799. #endif
  1800. return true;
  1801. }
  1802. //-----------------------------------------------------------------------------
  1803. // Purpose: Write vid.buffer out as a .jpg file
  1804. // Input : *pFilename -
  1805. //-----------------------------------------------------------------------------
  1806. void CVideoMode_Common::TakeSnapshotJPEG( const char *pFilename, int quality )
  1807. {
  1808. #if !defined( _X360 )
  1809. Assert( pFilename );
  1810. // Output buffer
  1811. CUtlBuffer buf( 0, 0 );
  1812. TakeSnapshotJPEGToBuffer( buf, quality );
  1813. int finalSize = 0;
  1814. FileHandle_t fh = g_pFileSystem->Open( pFilename, "wb" );
  1815. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1816. {
  1817. g_pFileSystem->Write( buf.Base(), buf.TellPut(), fh );
  1818. finalSize = g_pFileSystem->Tell( fh );
  1819. g_pFileSystem->Close( fh );
  1820. }
  1821. // Show info to console.
  1822. char orig[ 64 ];
  1823. char final[ 64 ];
  1824. Q_strncpy( orig, Q_pretifymem( GetModeStereoWidth() * 3 * GetModeStereoHeight(), 2 ), sizeof( orig ) );
  1825. Q_strncpy( final, Q_pretifymem( finalSize, 2 ), sizeof( final ) );
  1826. Msg( "Wrote '%s': %s (%dx%d) compresssed (quality %i) to %s\n",
  1827. pFilename, orig, GetModeStereoWidth(), GetModeStereoHeight(), quality, final );
  1828. if ( finalSize > 0 )
  1829. {
  1830. char szPath[MAX_PATH];
  1831. szPath[0] = 0;
  1832. if ( g_pFileSystem->GetLocalPath( pFilename, szPath, sizeof(szPath) ) )
  1833. {
  1834. AddScreenshotToSteam( szPath, GetModeStereoWidth(), GetModeStereoHeight() );
  1835. }
  1836. }
  1837. #else
  1838. Assert( 0 );
  1839. #endif
  1840. }
  1841. //-----------------------------------------------------------------------------
  1842. // The version of the VideoMode class for the material system
  1843. //-----------------------------------------------------------------------------
  1844. class CVideoMode_MaterialSystem: public CVideoMode_Common
  1845. {
  1846. public:
  1847. typedef CVideoMode_Common BaseClass;
  1848. CVideoMode_MaterialSystem( );
  1849. virtual bool Init( );
  1850. virtual void Shutdown( void );
  1851. virtual void SetGameWindow( void *hWnd );
  1852. virtual bool SetMode( int nWidth, int nHeight, bool bWindowed );
  1853. virtual void ReleaseVideo( void );
  1854. virtual void RestoreVideo( void );
  1855. virtual void AdjustForModeChange( void );
  1856. virtual void ReadScreenPixels( int x, int y, int w, int h, void *pBuffer, ImageFormat format );
  1857. private:
  1858. virtual void ReleaseFullScreen( void );
  1859. virtual void ChangeDisplaySettingsToFullscreen( int nWidth, int nHeight, int nBPP );
  1860. #ifdef WIN32
  1861. int m_nLastCDSWidth;
  1862. int m_nLastCDSHeight;
  1863. int m_nLastCDSBPP;
  1864. int m_nLastCDSFreq;
  1865. #endif
  1866. };
  1867. static void VideoMode_AdjustForModeChange( void )
  1868. {
  1869. ( ( CVideoMode_MaterialSystem * )videomode )->AdjustForModeChange();
  1870. }
  1871. //-----------------------------------------------------------------------------
  1872. // Constructor, destructor
  1873. //-----------------------------------------------------------------------------
  1874. CVideoMode_MaterialSystem::CVideoMode_MaterialSystem( )
  1875. {
  1876. #ifdef WIN32
  1877. m_nLastCDSWidth = 0;
  1878. m_nLastCDSHeight = 0;
  1879. m_nLastCDSBPP = 0;
  1880. m_nLastCDSFreq = 0;
  1881. #endif
  1882. }
  1883. //-----------------------------------------------------------------------------
  1884. // Initialization
  1885. //-----------------------------------------------------------------------------
  1886. bool CVideoMode_MaterialSystem::Init( )
  1887. {
  1888. m_bSetModeOnce = false;
  1889. m_bPlayedStartupVideo = false;
  1890. // we only support 32-bit rendering.
  1891. int bitsperpixel = 32;
  1892. bool bAllowSmallModes = false;
  1893. if ( CommandLine()->FindParm( "-small" ) )
  1894. {
  1895. bAllowSmallModes = true;
  1896. }
  1897. int nAdapter = materials->GetCurrentAdapter();
  1898. int nModeCount = materials->GetModeCount( nAdapter );
  1899. int nDesktopWidth, nDesktopHeight, nDesktopRefresh;
  1900. game->GetDesktopInfo( nDesktopWidth, nDesktopHeight, nDesktopRefresh );
  1901. for ( int i = 0; i < nModeCount; i++ )
  1902. {
  1903. MaterialVideoMode_t info;
  1904. materials->GetModeInfo( nAdapter, i, info );
  1905. if ( info.m_Width < 640 || info.m_Height < 480 )
  1906. {
  1907. if ( !bAllowSmallModes )
  1908. continue;
  1909. }
  1910. // make sure we don't already have this mode listed
  1911. bool bAlreadyInList = false;
  1912. for ( int j = 0; j < m_nNumModes; j++ )
  1913. {
  1914. if ( info.m_Width == m_rgModeList[ j ].width && info.m_Height == m_rgModeList[ j ].height )
  1915. {
  1916. // in VR mode we want the highest refresh rate, without regard for the desktop refresh rate
  1917. if ( UseVR() || ShouldForceVRActive() )
  1918. {
  1919. if ( info.m_RefreshRate > m_rgModeList[j].refreshRate )
  1920. {
  1921. m_rgModeList[j].refreshRate = info.m_RefreshRate;
  1922. }
  1923. }
  1924. else
  1925. {
  1926. // choose the highest refresh rate available for each mode up to the desktop rate
  1927. // if the new mode is valid and current is invalid or not as high, choose the new one
  1928. if ( info.m_RefreshRate <= nDesktopRefresh && (m_rgModeList[j].refreshRate > nDesktopRefresh || m_rgModeList[j].refreshRate < info.m_RefreshRate) )
  1929. {
  1930. m_rgModeList[j].refreshRate = info.m_RefreshRate;
  1931. }
  1932. }
  1933. bAlreadyInList = true;
  1934. break;
  1935. }
  1936. }
  1937. if ( bAlreadyInList )
  1938. continue;
  1939. m_rgModeList[ m_nNumModes ].width = info.m_Width;
  1940. m_rgModeList[ m_nNumModes ].height = info.m_Height;
  1941. m_rgModeList[ m_nNumModes ].bpp = bitsperpixel;
  1942. // NOTE: Don't clamp this to the desktop rate because we want to be sure we've only added
  1943. // modes that the adapter can do and maybe the desktop rate isn't available in this mode
  1944. m_rgModeList[ m_nNumModes ].refreshRate = info.m_RefreshRate;
  1945. if ( ++m_nNumModes >= MAX_MODE_LIST )
  1946. break;
  1947. }
  1948. // Sort modes for easy searching later
  1949. if ( m_nNumModes > 1 )
  1950. {
  1951. qsort( (void *)&m_rgModeList[0], m_nNumModes, sizeof(vmode_t), VideoModeCompare );
  1952. }
  1953. materials->AddModeChangeCallBack( &VideoMode_AdjustForModeChange );
  1954. SetInitialized( true );
  1955. return true;
  1956. }
  1957. void CVideoMode_MaterialSystem::Shutdown()
  1958. {
  1959. materials->RemoveModeChangeCallBack( &VideoMode_AdjustForModeChange );
  1960. BaseClass::Shutdown();
  1961. }
  1962. //-----------------------------------------------------------------------------
  1963. // Sets the video mode
  1964. //-----------------------------------------------------------------------------
  1965. bool CVideoMode_MaterialSystem::SetMode( int nWidth, int nHeight, bool bWindowed )
  1966. {
  1967. // Necessary for mode selection to work
  1968. int nFoundMode = FindVideoMode( nWidth, nHeight, bWindowed );
  1969. vmode_t *pMode = GetMode( nFoundMode );
  1970. // update current video state
  1971. MaterialSystem_Config_t config = *g_pMaterialSystemConfig;
  1972. config.m_VideoMode.m_Width = pMode->width;
  1973. config.m_VideoMode.m_Height = pMode->height;
  1974. // make sure VR mode is up to date
  1975. config.SetFlag( MATSYS_VIDCFG_FLAGS_VR_MODE, UseVR() || ShouldForceVRActive() );
  1976. if ( ShouldForceVRActive() )
  1977. {
  1978. config.m_nVRModeAdapter = materials->GetCurrentAdapter();
  1979. }
  1980. #ifdef SWDS
  1981. config.m_VideoMode.m_RefreshRate = 60;
  1982. #else
  1983. config.m_VideoMode.m_RefreshRate = GetRefreshRateForMode( pMode );
  1984. #endif
  1985. config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, bWindowed );
  1986. #if defined( _X360 )
  1987. XVIDEO_MODE videoMode;
  1988. XGetVideoMode( &videoMode );
  1989. if ( videoMode.fIsWideScreen )
  1990. {
  1991. extern ConVar r_aspectratio;
  1992. r_aspectratio.SetValue( 16.0f/9.0f );
  1993. }
  1994. config.SetFlag( MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION, (DWORD)nWidth != videoMode.dwDisplayWidth || (DWORD)nHeight != videoMode.dwDisplayHeight );
  1995. if ( nHeight == 480 || nWidth == 576 )
  1996. {
  1997. // Use 2xMSAA for standard def (see mat_software_aa_strength for fake hi-def aa)
  1998. // FIXME: shuffle the EDRAM surfaces to allow 4xMSAA for standard def
  1999. // (they would overlap & trash each other with the current arrangement)
  2000. // NOTE: This should affect 640x480 and 848x480 (which is also used for 640x480 widescreen), and PAL 640x576
  2001. config.m_nAASamples = 2;
  2002. }
  2003. #endif
  2004. // FIXME: This is trash. We have to do *different* things depending on how we're setting the mode!
  2005. if ( !m_bSetModeOnce )
  2006. {
  2007. //Debugger();
  2008. if ( !materials->SetMode( (void*)game->GetMainDeviceWindow(), config ) )
  2009. return false;
  2010. m_bSetModeOnce = true;
  2011. InitStartupScreen();
  2012. return true;
  2013. }
  2014. // update the config
  2015. OverrideMaterialSystemConfig( config );
  2016. return true;
  2017. }
  2018. //-----------------------------------------------------------------------------
  2019. // Called by the material system when mode changes after a call to OverrideConfig
  2020. //-----------------------------------------------------------------------------
  2021. void CVideoMode_MaterialSystem::AdjustForModeChange( void )
  2022. {
  2023. if ( InEditMode() )
  2024. return;
  2025. // get previous size
  2026. int nOldUIWidth = GetModeUIWidth();
  2027. int nOldUIHeight = GetModeUIHeight();
  2028. // Get the new mode info from the config record
  2029. int nNewWidth = g_pMaterialSystemConfig->m_VideoMode.m_Width;
  2030. int nNewHeight = g_pMaterialSystemConfig->m_VideoMode.m_Height;
  2031. bool bWindowed = g_pMaterialSystemConfig->Windowed();
  2032. // reset the window size
  2033. CMatRenderContextPtr pRenderContext( materials );
  2034. ResetCurrentModeForNewResolution( nNewWidth, nNewHeight, bWindowed );
  2035. AdjustWindow( GetModeWidth(), GetModeHeight(), GetModeBPP(), IsWindowedMode() );
  2036. MarkClientViewRectDirty();
  2037. pRenderContext->Viewport( 0, 0, GetModeStereoWidth(), GetModeStereoHeight() );
  2038. // fixup vgui
  2039. vgui::surface()->OnScreenSizeChanged( nOldUIWidth, nOldUIHeight );
  2040. // Re-init the HUD
  2041. ClientDLL_HudVidInit();
  2042. }
  2043. //-----------------------------------------------------------------------------
  2044. // Sets the game window in editor mode
  2045. //-----------------------------------------------------------------------------
  2046. void CVideoMode_MaterialSystem::SetGameWindow( void *hWnd )
  2047. {
  2048. if ( hWnd == NULL )
  2049. {
  2050. // No longer confine rendering into this view
  2051. materials->SetView( NULL );
  2052. return;
  2053. }
  2054. // When running in edit mode, just use hammer's window
  2055. game->SetGameWindow( (HWND)hWnd );
  2056. // FIXME: Move this code into the _MaterialSystem version of CVideoMode
  2057. // In editor mode, the mode width + height is equal to the desktop width + height
  2058. MaterialVideoMode_t mode;
  2059. materials->GetDisplayMode( mode );
  2060. m_bWindowed = true;
  2061. m_nModeWidth = mode.m_Width;
  2062. m_nModeHeight = mode.m_Height;
  2063. materials->SetView( game->GetMainDeviceWindow() );
  2064. }
  2065. //-----------------------------------------------------------------------------
  2066. // Called when we lose the video buffer (alt-tab)
  2067. //-----------------------------------------------------------------------------
  2068. void CVideoMode_MaterialSystem::ReleaseVideo( void )
  2069. {
  2070. if ( IsX360() )
  2071. return;
  2072. if ( IsWindowedMode() )
  2073. return;
  2074. ReleaseFullScreen();
  2075. }
  2076. //-----------------------------------------------------------------------------
  2077. // Purpose:
  2078. //-----------------------------------------------------------------------------
  2079. void CVideoMode_MaterialSystem::RestoreVideo( void )
  2080. {
  2081. if ( IsX360() )
  2082. return;
  2083. if ( IsWindowedMode() )
  2084. return;
  2085. #if defined( USE_SDL )
  2086. SDL_ShowWindow( (SDL_Window*)game->GetMainWindow() );
  2087. #else
  2088. ShowWindow( (HWND)game->GetMainWindow(), SW_SHOWNORMAL );
  2089. #endif
  2090. AdjustWindow( GetModeWidth(), GetModeHeight(), GetModeBPP(), IsWindowedMode() );
  2091. }
  2092. //-----------------------------------------------------------------------------
  2093. // Purpose:
  2094. //-----------------------------------------------------------------------------
  2095. void CVideoMode_MaterialSystem::ReleaseFullScreen( void )
  2096. {
  2097. if ( IsX360() )
  2098. return;
  2099. if ( IsWindowedMode() )
  2100. return;
  2101. #if !defined( USE_SDL )
  2102. // Hide the main window
  2103. if ( m_nLastCDSWidth != 0 )
  2104. ChangeDisplaySettings( NULL, 0 );
  2105. ShowWindow( (HWND)game->GetMainWindow(), SW_MINIMIZE );
  2106. m_nLastCDSWidth = 0;
  2107. m_nLastCDSHeight = 0;
  2108. m_nLastCDSBPP = 0;
  2109. m_nLastCDSFreq = 0;
  2110. #endif
  2111. }
  2112. //-----------------------------------------------------------------------------
  2113. // Purpose: Use Change Display Settings to go Full Screen
  2114. //-----------------------------------------------------------------------------
  2115. void CVideoMode_MaterialSystem::ChangeDisplaySettingsToFullscreen( int nWidth, int nHeight, int nBPP )
  2116. {
  2117. if ( IsX360() )
  2118. return;
  2119. if ( IsWindowedMode() )
  2120. return;
  2121. #if defined( WIN32 ) && !defined( USE_SDL )
  2122. DEVMODE dm;
  2123. memset(&dm, 0, sizeof(dm));
  2124. dm.dmSize = sizeof( dm );
  2125. dm.dmPelsWidth = nWidth;
  2126. dm.dmPelsHeight = nHeight;
  2127. dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  2128. dm.dmBitsPerPel = nBPP;
  2129. // FIXME: Fix direct reference of refresh rate from config record
  2130. int freq = g_pMaterialSystemConfig->m_VideoMode.m_RefreshRate;
  2131. if ( freq >= 60 )
  2132. {
  2133. dm.dmDisplayFrequency = freq;
  2134. dm.dmFields |= DM_DISPLAYFREQUENCY;
  2135. }
  2136. #if defined(IS_WINDOWS_PC)
  2137. DEVMODE dmCurrent;
  2138. if ( EnumDisplaySettings( materials->GetDisplayDeviceName(), ENUM_CURRENT_SETTINGS, &dmCurrent ) &&
  2139. dmCurrent.dmBitsPerPel == dm.dmBitsPerPel &&
  2140. dmCurrent.dmPelsWidth == dm.dmPelsWidth &&
  2141. dmCurrent.dmPelsHeight == dm.dmPelsHeight &&
  2142. ( (dm.dmFields & DM_DISPLAYFREQUENCY) == 0 || dmCurrent.dmDisplayFrequency == dm.dmDisplayFrequency ) )
  2143. {
  2144. return;
  2145. }
  2146. #endif
  2147. if ( nWidth == m_nLastCDSWidth && nHeight == m_nLastCDSHeight && nBPP == m_nLastCDSBPP && freq == m_nLastCDSFreq )
  2148. return;
  2149. m_nLastCDSWidth = nWidth;
  2150. m_nLastCDSHeight = nHeight;
  2151. m_nLastCDSBPP = nBPP;
  2152. m_nLastCDSFreq = freq;
  2153. ChangeDisplaySettingsEx( materials->GetDisplayDeviceName(), &dm, NULL, CDS_FULLSCREEN, NULL );
  2154. #elif defined( USE_SDL )
  2155. g_pLauncherMgr->SetWindowFullScreen( true, nWidth, nHeight );
  2156. #else
  2157. if ( !HushAsserts() )
  2158. {
  2159. Assert( !"Impl me" );
  2160. }
  2161. #endif
  2162. }
  2163. void CVideoMode_MaterialSystem::ReadScreenPixels( int x, int y, int w, int h, void *pBuffer, ImageFormat format )
  2164. {
  2165. if ( !g_LostVideoMemory )
  2166. {
  2167. bool bReadPixelsFromFrontBuffer = g_pMaterialSystemHardwareConfig->ReadPixelsFromFrontBuffer();
  2168. if( bReadPixelsFromFrontBuffer )
  2169. {
  2170. Shader_SwapBuffers();
  2171. }
  2172. CMatRenderContextPtr pRenderContext( materials );
  2173. Rect_t rect;
  2174. rect.x = x;
  2175. rect.y = y;
  2176. rect.width = w;
  2177. rect.height = h;
  2178. pRenderContext->ReadPixelsAndStretch( &rect, &rect, (unsigned char*)pBuffer, format, w * ImageLoader::SizeInBytes( format ) );
  2179. if( bReadPixelsFromFrontBuffer )
  2180. {
  2181. Shader_SwapBuffers();
  2182. }
  2183. }
  2184. else
  2185. {
  2186. int nBytes = ImageLoader::GetMemRequired( w, h, 1, format, false );
  2187. memset( pBuffer, 0, nBytes );
  2188. }
  2189. }
  2190. //-----------------------------------------------------------------------------
  2191. // Class factory
  2192. //-----------------------------------------------------------------------------
  2193. IVideoMode *videomode = ( IVideoMode * )NULL;
  2194. void VideoMode_Create( )
  2195. {
  2196. videomode = new CVideoMode_MaterialSystem;
  2197. Assert( videomode );
  2198. }
  2199. void VideoMode_Destroy()
  2200. {
  2201. if ( videomode )
  2202. {
  2203. CVideoMode_MaterialSystem *pVideoMode_MS = static_cast<CVideoMode_MaterialSystem*>(videomode);
  2204. delete pVideoMode_MS;
  2205. videomode = NULL;
  2206. }
  2207. }