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.

2712 lines
83 KiB

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