Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1763 lines
52 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "OptionsSubVideo.h"
  8. #include "cvarslider.h"
  9. #include "EngineInterface.h"
  10. #include "BasePanel.h"
  11. #include "IGameUIFuncs.h"
  12. #include "modes.h"
  13. #include "materialsystem/materialsystem_config.h"
  14. #include "filesystem.h"
  15. #include "GameUI_Interface.h"
  16. #include "vgui_controls/CheckButton.h"
  17. #include "vgui_controls/ComboBox.h"
  18. #include "vgui_controls/Frame.h"
  19. #include "vgui_controls/QueryBox.h"
  20. #include "CvarToggleCheckButton.h"
  21. #include "tier1/KeyValues.h"
  22. #include "vgui/IInput.h"
  23. #include "vgui/ILocalize.h"
  24. #include "vgui/ISystem.h"
  25. #include "tier0/icommandline.h"
  26. #include "tier1/convar.h"
  27. #include "ModInfo.h"
  28. #include "vgui_controls/Tooltip.h"
  29. #include "sourcevr/isourcevirtualreality.h"
  30. #if defined( USE_SDL )
  31. #include "SDL.h"
  32. #endif
  33. #include "inetchannelinfo.h"
  34. extern IMaterialSystem *materials;
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. using namespace vgui;
  38. //-----------------------------------------------------------------------------
  39. // Purpose: aspect ratio mappings (for normal/widescreen combo)
  40. //-----------------------------------------------------------------------------
  41. struct RatioToAspectMode_t
  42. {
  43. int anamorphic;
  44. float aspectRatio;
  45. };
  46. RatioToAspectMode_t g_RatioToAspectModes[] =
  47. {
  48. { 0, 4.0f / 3.0f },
  49. { 1, 16.0f / 9.0f },
  50. { 2, 16.0f / 10.0f },
  51. { 2, 1.0f },
  52. };
  53. struct AAMode_t
  54. {
  55. int m_nNumSamples;
  56. int m_nQualityLevel;
  57. };
  58. //-----------------------------------------------------------------------------
  59. // Purpose: list of valid dx levels
  60. //-----------------------------------------------------------------------------
  61. int g_DirectXLevels[] =
  62. {
  63. 70,
  64. 80,
  65. 81,
  66. 90,
  67. #if DX_TO_GL_ABSTRACTION
  68. 92,
  69. #endif
  70. 95,
  71. };
  72. //-----------------------------------------------------------------------------
  73. // Purpose: returns the string name of a given dxlevel
  74. //-----------------------------------------------------------------------------
  75. void GetNameForDXLevel( int dxlevel, char *name, int bufferSize)
  76. {
  77. if ( ( dxlevel >= 92 ) && ( dxlevel <= 95 ) )
  78. {
  79. Q_snprintf( name, bufferSize, "DirectX v9.0+" );
  80. }
  81. else
  82. {
  83. Q_snprintf( name, bufferSize, "DirectX v%.1f", dxlevel / 10.0f );
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose: returns the aspect ratio mode number for the given resolution
  88. //-----------------------------------------------------------------------------
  89. int GetScreenAspectMode( int width, int height )
  90. {
  91. float aspectRatio = (float)width / (float)height;
  92. // just find the closest ratio
  93. float closestAspectRatioDist = 99999.0f;
  94. int closestAnamorphic = 0;
  95. for (int i = 0; i < ARRAYSIZE(g_RatioToAspectModes); i++)
  96. {
  97. float dist = fabs( g_RatioToAspectModes[i].aspectRatio - aspectRatio );
  98. if (dist < closestAspectRatioDist)
  99. {
  100. closestAspectRatioDist = dist;
  101. closestAnamorphic = g_RatioToAspectModes[i].anamorphic;
  102. }
  103. }
  104. return closestAnamorphic;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose: returns the string name of the specified resolution mode
  108. //-----------------------------------------------------------------------------
  109. static void GetResolutionName( vmode_t *mode, char *sz, int sizeofsz, int desktopWidth, int desktopHeight )
  110. {
  111. Q_snprintf( sz, sizeofsz, "%i x %i%s", mode->width, mode->height,
  112. ( mode->width == desktopWidth ) && ( mode->height == desktopHeight ) ? " (native)": "" );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Gamma-adjust dialog
  116. //-----------------------------------------------------------------------------
  117. class CGammaDialog : public vgui::Frame
  118. {
  119. DECLARE_CLASS_SIMPLE( CGammaDialog, vgui::Frame );
  120. public:
  121. CGammaDialog( vgui::VPANEL hParent ) : BaseClass( NULL, "OptionsSubVideoGammaDlg" )
  122. {
  123. // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
  124. SetTitle("#GameUI_AdjustGamma_Title", true);
  125. SetSize( 400, 260 );
  126. SetDeleteSelfOnClose( true );
  127. m_pGammaSlider = new CCvarSlider( this, "Gamma", "#GameUI_Gamma", 1.6f, 2.6f, "mat_monitorgamma" );
  128. m_pGammaLabel = new Label( this, "Gamma label", "#GameUI_Gamma" );
  129. m_pGammaEntry = new TextEntry( this, "GammaEntry" );
  130. Button *ok = new Button( this, "OKButton", "#vgui_ok" );
  131. ok->SetCommand( new KeyValues("OK") );
  132. LoadControlSettings( "resource/OptionsSubVideoGammaDlg.res" );
  133. MoveToCenterOfScreen();
  134. SetSizeable( false );
  135. m_pGammaSlider->SetTickCaptions( "#GameUI_Light", "#GameUI_Dark" );
  136. }
  137. MESSAGE_FUNC_PTR( OnGammaChanged, "SliderMoved", panel )
  138. {
  139. if (panel == m_pGammaSlider)
  140. {
  141. m_pGammaSlider->ApplyChanges();
  142. }
  143. }
  144. virtual void Activate()
  145. {
  146. BaseClass::Activate();
  147. m_flOriginalGamma = m_pGammaSlider->GetValue();
  148. UpdateGammaLabel();
  149. }
  150. MESSAGE_FUNC( OnOK, "OK" )
  151. {
  152. // make the gamma stick
  153. m_flOriginalGamma = m_pGammaSlider->GetValue();
  154. Close();
  155. }
  156. virtual void OnClose()
  157. {
  158. // reset to the original gamma
  159. m_pGammaSlider->SetValue( m_flOriginalGamma );
  160. m_pGammaSlider->ApplyChanges();
  161. BaseClass::OnClose();
  162. }
  163. void OnKeyCodeTyped(KeyCode code)
  164. {
  165. // force ourselves to be closed if the escape key it pressed
  166. if (code == KEY_ESCAPE)
  167. {
  168. Close();
  169. }
  170. else
  171. {
  172. BaseClass::OnKeyCodeTyped(code);
  173. }
  174. }
  175. MESSAGE_FUNC_PTR( OnControlModified, "ControlModified", panel )
  176. {
  177. // the HasBeenModified() check is so that if the value is outside of the range of the
  178. // slider, it won't use the slider to determine the display value but leave the
  179. // real value that we determined in the constructor
  180. if (panel == m_pGammaSlider && m_pGammaSlider->HasBeenModified())
  181. {
  182. UpdateGammaLabel();
  183. }
  184. }
  185. MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel )
  186. {
  187. if (panel == m_pGammaEntry)
  188. {
  189. char buf[64];
  190. m_pGammaEntry->GetText(buf, 64);
  191. float fValue = (float) atof(buf);
  192. if (fValue >= 1.0)
  193. {
  194. m_pGammaSlider->SetSliderValue(fValue);
  195. PostActionSignal(new KeyValues("ApplyButtonEnable"));
  196. }
  197. }
  198. }
  199. void UpdateGammaLabel()
  200. {
  201. char buf[64];
  202. Q_snprintf(buf, sizeof( buf ), " %.1f", m_pGammaSlider->GetSliderValue());
  203. m_pGammaEntry->SetText(buf);
  204. }
  205. private:
  206. CCvarSlider *m_pGammaSlider;
  207. vgui::Label *m_pGammaLabel;
  208. vgui::TextEntry *m_pGammaEntry;
  209. float m_flOriginalGamma;
  210. };
  211. //-----------------------------------------------------------------------------
  212. // Purpose: advanced keyboard settings dialog
  213. //-----------------------------------------------------------------------------
  214. class COptionsSubVideoAdvancedDlg : public vgui::Frame
  215. {
  216. DECLARE_CLASS_SIMPLE( COptionsSubVideoAdvancedDlg, vgui::Frame );
  217. public:
  218. COptionsSubVideoAdvancedDlg( vgui::Panel *parent ) : BaseClass( parent , "OptionsSubVideoAdvancedDlg" )
  219. {
  220. SetTitle("#GameUI_VideoAdvanced_Title", true);
  221. SetSize( 260, 400 );
  222. m_pDXLevel = new ComboBox(this, "dxlabel", 6, false );
  223. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  224. KeyValues *pKeyValues = new KeyValues( "config" );
  225. materials->GetRecommendedConfigurationInfo( 0, pKeyValues );
  226. m_pDXLevel->DeleteAllItems();
  227. for (int i = 0; i < ARRAYSIZE(g_DirectXLevels); i++)
  228. {
  229. // don't allow choice of lower dxlevels than the default,
  230. // unless we're already at that lower level or have it forced
  231. if (!CommandLine()->CheckParm("-dxlevel") &&
  232. g_DirectXLevels[i] != config.dxSupportLevel &&
  233. g_DirectXLevels[i] < pKeyValues->GetInt("ConVar.mat_dxlevel"))
  234. continue;
  235. KeyValues *pTempKV = new KeyValues("config");
  236. if (g_DirectXLevels[i] == pKeyValues->GetInt("ConVar.mat_dxlevel")
  237. || materials->GetRecommendedConfigurationInfo( g_DirectXLevels[i], pTempKV ))
  238. {
  239. // add the configuration in the combo
  240. char szDXLevelName[64];
  241. GetNameForDXLevel( g_DirectXLevels[i], szDXLevelName, sizeof(szDXLevelName) );
  242. m_pDXLevel->AddItem( szDXLevelName, new KeyValues("dxlevel", "dxlevel", g_DirectXLevels[i]) );
  243. }
  244. pTempKV->deleteThis();
  245. }
  246. pKeyValues->deleteThis();
  247. m_pModelDetail = new ComboBox( this, "ModelDetail", 6, false );
  248. m_pModelDetail->AddItem("#gameui_low", NULL);
  249. m_pModelDetail->AddItem("#gameui_medium", NULL);
  250. m_pModelDetail->AddItem("#gameui_high", NULL);
  251. m_pTextureDetail = new ComboBox( this, "TextureDetail", 6, false );
  252. m_pTextureDetail->AddItem("#gameui_low", NULL);
  253. m_pTextureDetail->AddItem("#gameui_medium", NULL);
  254. m_pTextureDetail->AddItem("#gameui_high", NULL);
  255. m_pTextureDetail->AddItem("#gameui_ultra", NULL);
  256. // Build list of MSAA and CSAA modes, based upon those which are supported by the device
  257. //
  258. // The modes that we've seen in the wild to date are as follows (in perf order, fastest to slowest)
  259. //
  260. // 2x 4x 6x 8x 16x 8x 16xQ
  261. // Texture/Shader Samples 1 1 1 1 1 1 1
  262. // Stored Color/Z Samples 2 4 6 4 4 8 8
  263. // Coverage Samples 2 4 6 8 16 8 16
  264. // MSAA or CSAA M M M C C M C
  265. //
  266. // The CSAA modes are nVidia only (added in the G80 generation of GPUs)
  267. //
  268. m_nNumAAModes = 0;
  269. m_pAntialiasingMode = new ComboBox( this, "AntialiasingMode", 10, false );
  270. m_pAntialiasingMode->AddItem("#GameUI_None", NULL);
  271. m_nAAModes[m_nNumAAModes].m_nNumSamples = 1;
  272. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
  273. m_nNumAAModes++;
  274. if ( materials->SupportsMSAAMode(2) )
  275. {
  276. m_pAntialiasingMode->AddItem("#GameUI_2X", NULL);
  277. m_nAAModes[m_nNumAAModes].m_nNumSamples = 2;
  278. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
  279. m_nNumAAModes++;
  280. }
  281. if ( materials->SupportsMSAAMode(4) )
  282. {
  283. m_pAntialiasingMode->AddItem("#GameUI_4X", NULL);
  284. m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
  285. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
  286. m_nNumAAModes++;
  287. }
  288. if ( materials->SupportsMSAAMode(6) )
  289. {
  290. m_pAntialiasingMode->AddItem("#GameUI_6X", NULL);
  291. m_nAAModes[m_nNumAAModes].m_nNumSamples = 6;
  292. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
  293. m_nNumAAModes++;
  294. }
  295. if ( materials->SupportsCSAAMode(4, 2) ) // nVidia CSAA "8x"
  296. {
  297. m_pAntialiasingMode->AddItem("#GameUI_8X_CSAA", NULL);
  298. m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
  299. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 2;
  300. m_nNumAAModes++;
  301. }
  302. if ( materials->SupportsCSAAMode(4, 4) ) // nVidia CSAA "16x"
  303. {
  304. m_pAntialiasingMode->AddItem("#GameUI_16X_CSAA", NULL);
  305. m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
  306. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 4;
  307. m_nNumAAModes++;
  308. }
  309. if ( materials->SupportsMSAAMode(8) )
  310. {
  311. m_pAntialiasingMode->AddItem("#GameUI_8X", NULL);
  312. m_nAAModes[m_nNumAAModes].m_nNumSamples = 8;
  313. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
  314. m_nNumAAModes++;
  315. }
  316. if ( materials->SupportsCSAAMode(8, 2) ) // nVidia CSAA "16xQ"
  317. {
  318. m_pAntialiasingMode->AddItem("#GameUI_16XQ_CSAA", NULL);
  319. m_nAAModes[m_nNumAAModes].m_nNumSamples = 8;
  320. m_nAAModes[m_nNumAAModes].m_nQualityLevel = 2;
  321. m_nNumAAModes++;
  322. }
  323. m_pFilteringMode = new ComboBox( this, "FilteringMode", 6, false );
  324. m_pFilteringMode->AddItem("#GameUI_Bilinear", NULL);
  325. m_pFilteringMode->AddItem("#GameUI_Trilinear", NULL);
  326. m_pFilteringMode->AddItem("#GameUI_Anisotropic2X", NULL);
  327. m_pFilteringMode->AddItem("#GameUI_Anisotropic4X", NULL);
  328. m_pFilteringMode->AddItem("#GameUI_Anisotropic8X", NULL);
  329. m_pFilteringMode->AddItem("#GameUI_Anisotropic16X", NULL);
  330. m_pShadowDetail = new ComboBox( this, "ShadowDetail", 6, false );
  331. m_pShadowDetail->AddItem("#gameui_low", NULL);
  332. m_pShadowDetail->AddItem("#gameui_medium", NULL);
  333. if ( materials->SupportsShadowDepthTextures() )
  334. {
  335. m_pShadowDetail->AddItem("#gameui_high", NULL);
  336. }
  337. ConVarRef mat_dxlevel( "mat_dxlevel" );
  338. m_pHDR = new ComboBox( this, "HDR", 6, false );
  339. m_pHDR->AddItem("#GameUI_hdr_level0", NULL);
  340. m_pHDR->AddItem("#GameUI_hdr_level1", NULL);
  341. if ( materials->SupportsHDRMode( HDR_TYPE_INTEGER ) )
  342. {
  343. m_pHDR->AddItem("#GameUI_hdr_level2", NULL);
  344. }
  345. #if 0
  346. if ( materials->SupportsHDRMode( HDR_TYPE_FLOAT ) )
  347. {
  348. m_pHDR->AddItem("#GameUI_hdr_level3", NULL);
  349. }
  350. #endif
  351. m_pHDR->SetEnabled( mat_dxlevel.GetInt() >= 80 );
  352. m_pWaterDetail = new ComboBox( this, "WaterDetail", 6, false );
  353. m_pWaterDetail->AddItem("#gameui_noreflections", NULL);
  354. m_pWaterDetail->AddItem("#gameui_reflectonlyworld", NULL);
  355. m_pWaterDetail->AddItem("#gameui_reflectall", NULL);
  356. m_pVSync = new ComboBox( this, "VSync", 2, false );
  357. m_pVSync->AddItem("#gameui_disabled", NULL);
  358. m_pVSync->AddItem("#gameui_enabled", NULL);
  359. m_pMulticore = new ComboBox( this, "Multicore", 2, false );
  360. m_pMulticore->AddItem("#gameui_disabled", NULL);
  361. m_pMulticore->AddItem("#gameui_enabled", NULL);
  362. m_pShaderDetail = new ComboBox( this, "ShaderDetail", 6, false );
  363. m_pShaderDetail->AddItem("#gameui_low", NULL);
  364. m_pShaderDetail->AddItem("#gameui_high", NULL);
  365. m_pColorCorrection = new ComboBox( this, "ColorCorrection", 2, false );
  366. m_pColorCorrection->AddItem("#gameui_disabled", NULL);
  367. m_pColorCorrection->AddItem("#gameui_enabled", NULL);
  368. m_pMotionBlur = new ComboBox( this, "MotionBlur", 2, false );
  369. m_pMotionBlur->AddItem("#gameui_disabled", NULL);
  370. m_pMotionBlur->AddItem("#gameui_enabled", NULL);
  371. LoadControlSettings( "resource/OptionsSubVideoAdvancedDlg.res" );
  372. MoveToCenterOfScreen();
  373. SetSizeable( false );
  374. m_pDXLevel->SetEnabled(false);
  375. m_pColorCorrection->SetEnabled( mat_dxlevel.GetInt() >= 90 );
  376. m_pMotionBlur->SetEnabled( mat_dxlevel.GetInt() >= 90 );
  377. if ( g_pCVar->FindVar( "fov_desired" ) == NULL )
  378. {
  379. Panel *pFOV = FindChildByName( "FovSlider" );
  380. if ( pFOV )
  381. {
  382. pFOV->SetVisible( false );
  383. }
  384. pFOV = FindChildByName( "FovLabel" );
  385. if ( pFOV )
  386. {
  387. pFOV->SetVisible( false );
  388. }
  389. }
  390. MarkDefaultSettingsAsRecommended();
  391. m_bUseChanges = false;
  392. }
  393. virtual void Activate()
  394. {
  395. BaseClass::Activate();
  396. input()->SetAppModalSurface(GetVPanel());
  397. if (!m_bUseChanges)
  398. {
  399. // reset the data
  400. OnResetData();
  401. }
  402. }
  403. void SetComboItemAsRecommended( vgui::ComboBox *combo, int iItem )
  404. {
  405. // get the item text
  406. wchar_t text[512];
  407. combo->GetItemText(iItem, text, sizeof(text));
  408. // append the recommended flag
  409. wchar_t newText[512];
  410. _snwprintf( newText, sizeof(newText) / sizeof(wchar_t), L"%ls *", text );
  411. // reset
  412. combo->UpdateItem(iItem, newText, NULL);
  413. }
  414. int FindMSAAMode( int nAASamples, int nAAQuality )
  415. {
  416. // Run through the AA Modes supported by the device
  417. for ( int nAAMode = 0; nAAMode < m_nNumAAModes; nAAMode++ )
  418. {
  419. // If we found the mode that matches what we're looking for, return the index
  420. if ( ( m_nAAModes[nAAMode].m_nNumSamples == nAASamples) && ( m_nAAModes[nAAMode].m_nQualityLevel == nAAQuality) )
  421. {
  422. return nAAMode;
  423. }
  424. }
  425. return 0; // Didn't find what we're looking for, so no AA
  426. }
  427. MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel )
  428. {
  429. if ( panel == m_pDXLevel && RequiresRestart() )
  430. {
  431. // notify the user that this will require a disconnect
  432. QueryBox *box = new QueryBox("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info");
  433. box->AddActionSignalTarget( this );
  434. box->SetCancelCommand(new KeyValues("ResetDXLevelCombo"));
  435. box->DoModal();
  436. }
  437. }
  438. MESSAGE_FUNC( OnGameUIHidden, "GameUIHidden" ) // called when the GameUI is hidden
  439. {
  440. Close();
  441. }
  442. MESSAGE_FUNC( ResetDXLevelCombo, "ResetDXLevelCombo" )
  443. {
  444. ConVarRef mat_dxlevel( "mat_dxlevel" );
  445. for (int i = 0; i < m_pDXLevel->GetItemCount(); i++)
  446. {
  447. KeyValues *kv = m_pDXLevel->GetItemUserData(i);
  448. if ( kv->GetInt("dxlevel") == mat_dxlevel.GetInt( ) )
  449. {
  450. m_pDXLevel->ActivateItem( i );
  451. break;
  452. }
  453. }
  454. // Reset HDR too
  455. if ( m_pHDR->IsEnabled() )
  456. {
  457. ConVarRef mat_hdr_level("mat_hdr_level");
  458. Assert( mat_hdr_level.IsValid() );
  459. m_pHDR->ActivateItem( clamp( mat_hdr_level.GetInt(), 0, 2 ) );
  460. }
  461. }
  462. MESSAGE_FUNC( OK_Confirmed, "OK_Confirmed" )
  463. {
  464. m_bUseChanges = true;
  465. Close();
  466. }
  467. void MarkDefaultSettingsAsRecommended()
  468. {
  469. // Pull in data from dxsupport.cfg database (includes fine-grained per-vendor/per-device config data)
  470. KeyValues *pKeyValues = new KeyValues( "config" );
  471. materials->GetRecommendedConfigurationInfo( 0, pKeyValues );
  472. // Read individual values from keyvalues which came from dxsupport.cfg database
  473. int nSkipLevels = pKeyValues->GetInt( "ConVar.mat_picmip", 0 );
  474. int nAnisotropicLevel = pKeyValues->GetInt( "ConVar.mat_forceaniso", 1 );
  475. int nForceTrilinear = pKeyValues->GetInt( "ConVar.mat_trilinear", 0 );
  476. int nAASamples = pKeyValues->GetInt( "ConVar.mat_antialias", 0 );
  477. int nAAQuality = pKeyValues->GetInt( "ConVar.mat_aaquality", 0 );
  478. int nRenderToTextureShadows = pKeyValues->GetInt( "ConVar.r_shadowrendertotexture", 0 );
  479. int nShadowDepthTextureShadows = pKeyValues->GetInt( "ConVar.r_flashlightdepthtexture", 0 );
  480. #ifndef _X360
  481. int nWaterUseRealtimeReflection = pKeyValues->GetInt( "ConVar.r_waterforceexpensive", 0 );
  482. #endif
  483. int nWaterUseEntityReflection = pKeyValues->GetInt( "ConVar.r_waterforcereflectentities", 0 );
  484. int nMatVSync = pKeyValues->GetInt( "ConVar.mat_vsync", 1 );
  485. int nRootLOD = pKeyValues->GetInt( "ConVar.r_rootlod", 0 );
  486. int nReduceFillRate = pKeyValues->GetInt( "ConVar.mat_reducefillrate", 0 );
  487. int nDXLevel = pKeyValues->GetInt( "ConVar.mat_dxlevel", 0 );
  488. int nColorCorrection = pKeyValues->GetInt( "ConVar.mat_colorcorrection", 0 );
  489. int nMotionBlur = pKeyValues->GetInt( "ConVar.mat_motion_blur_enabled", 0 );
  490. // It doesn't make sense to retrieve this convar from dxsupport, because we'll then have materialsystem setting this config at loadtime. (Also, it only has very minimal support for CPU related configuration.)
  491. //int nMulticore = pKeyValues->GetInt( "ConVar.mat_queue_mode", 0 );
  492. int nMulticore = GetCPUInformation()->m_nPhysicalProcessors >= 2;
  493. // Only recommend a dxlevel if there is more than one available
  494. if ( m_pDXLevel->GetItemCount() > 1 )
  495. {
  496. for (int i = 0; i < m_pDXLevel->GetItemCount(); i++)
  497. {
  498. KeyValues *kv = m_pDXLevel->GetItemUserData(i);
  499. if (kv->GetInt("dxlevel") == pKeyValues->GetInt("ConVar.mat_dxlevel"))
  500. {
  501. SetComboItemAsRecommended( m_pDXLevel, i );
  502. break;
  503. }
  504. }
  505. }
  506. SetComboItemAsRecommended( m_pModelDetail, 2 - nRootLOD );
  507. SetComboItemAsRecommended( m_pTextureDetail, 2 - nSkipLevels );
  508. switch ( nAnisotropicLevel )
  509. {
  510. case 2:
  511. SetComboItemAsRecommended( m_pFilteringMode, 2 );
  512. break;
  513. case 4:
  514. SetComboItemAsRecommended( m_pFilteringMode, 3 );
  515. break;
  516. case 8:
  517. SetComboItemAsRecommended( m_pFilteringMode, 4 );
  518. break;
  519. case 16:
  520. SetComboItemAsRecommended( m_pFilteringMode, 5 );
  521. break;
  522. case 0:
  523. default:
  524. if ( nForceTrilinear != 0 )
  525. {
  526. SetComboItemAsRecommended( m_pFilteringMode, 1 );
  527. }
  528. else
  529. {
  530. SetComboItemAsRecommended( m_pFilteringMode, 0 );
  531. }
  532. break;
  533. }
  534. // Map desired mode to list item number
  535. int nMSAAMode = FindMSAAMode( nAASamples, nAAQuality );
  536. SetComboItemAsRecommended( m_pAntialiasingMode, nMSAAMode );
  537. if ( nShadowDepthTextureShadows )
  538. SetComboItemAsRecommended( m_pShadowDetail, 2 ); // Shadow depth mapping (in addition to RTT shadows)
  539. else if ( nRenderToTextureShadows )
  540. SetComboItemAsRecommended( m_pShadowDetail, 1 ); // RTT shadows
  541. else
  542. SetComboItemAsRecommended( m_pShadowDetail, 0 ); // Blobbies
  543. SetComboItemAsRecommended( m_pShaderDetail, nReduceFillRate ? 0 : 1 );
  544. #ifndef _X360
  545. if ( nWaterUseRealtimeReflection )
  546. #endif
  547. {
  548. if ( nWaterUseEntityReflection )
  549. {
  550. SetComboItemAsRecommended( m_pWaterDetail, 2 );
  551. }
  552. else
  553. {
  554. SetComboItemAsRecommended( m_pWaterDetail, 1 );
  555. }
  556. }
  557. #ifndef _X360
  558. else
  559. {
  560. SetComboItemAsRecommended( m_pWaterDetail, 0 );
  561. }
  562. #endif
  563. SetComboItemAsRecommended( m_pVSync, nMatVSync != 0 );
  564. SetComboItemAsRecommended( m_pMulticore, nMulticore != 0 );
  565. SetComboItemAsRecommended( m_pHDR, nDXLevel >= 90 ? 2 : 0 );
  566. SetComboItemAsRecommended( m_pColorCorrection, nColorCorrection );
  567. SetComboItemAsRecommended( m_pMotionBlur, nMotionBlur );
  568. pKeyValues->deleteThis();
  569. }
  570. void ApplyChangesToConVar( const char *pConVarName, int value )
  571. {
  572. Assert( cvar->FindVar( pConVarName ) );
  573. char szCmd[256];
  574. Q_snprintf( szCmd, sizeof(szCmd), "%s %d\n", pConVarName, value );
  575. engine->ClientCmd_Unrestricted( szCmd );
  576. }
  577. virtual void ApplyChanges()
  578. {
  579. if ( !m_bUseChanges )
  580. return;
  581. KeyValues *pActiveItem = m_pDXLevel->GetActiveItemUserData();
  582. if ( pActiveItem )
  583. {
  584. ApplyChangesToConVar( "mat_dxlevel", pActiveItem->GetInt( "dxlevel" ) );
  585. }
  586. ApplyChangesToConVar( "r_rootlod", 2 - m_pModelDetail->GetActiveItem());
  587. ApplyChangesToConVar( "mat_picmip", 2 - m_pTextureDetail->GetActiveItem());
  588. // reset everything tied to the filtering mode, then the switch sets the appropriate one
  589. ApplyChangesToConVar( "mat_trilinear", false );
  590. ApplyChangesToConVar( "mat_forceaniso", 1 );
  591. switch ( m_pFilteringMode->GetActiveItem() )
  592. {
  593. case 0:
  594. break;
  595. case 1:
  596. ApplyChangesToConVar( "mat_trilinear", true );
  597. break;
  598. case 2:
  599. ApplyChangesToConVar( "mat_forceaniso", 2 );
  600. break;
  601. case 3:
  602. ApplyChangesToConVar( "mat_forceaniso", 4 );
  603. break;
  604. case 4:
  605. ApplyChangesToConVar( "mat_forceaniso", 8 );
  606. break;
  607. case 5:
  608. ApplyChangesToConVar( "mat_forceaniso", 16 );
  609. break;
  610. default:
  611. // Trilinear.
  612. ApplyChangesToConVar( "mat_forceaniso", 1 );
  613. break;
  614. }
  615. // Set the AA convars according to the menu item chosen
  616. int nActiveAAItem = m_pAntialiasingMode->GetActiveItem();
  617. ApplyChangesToConVar( "mat_antialias", m_nAAModes[nActiveAAItem].m_nNumSamples );
  618. ApplyChangesToConVar( "mat_aaquality", m_nAAModes[nActiveAAItem].m_nQualityLevel );
  619. if( m_pHDR->IsEnabled() )
  620. {
  621. ConVarRef mat_hdr_level("mat_hdr_level");
  622. Assert( mat_hdr_level.IsValid() );
  623. mat_hdr_level.SetValue(m_pHDR->GetActiveItem());
  624. }
  625. if ( m_pShadowDetail->GetActiveItem() == 0 ) // Blobby shadows
  626. {
  627. ApplyChangesToConVar( "r_shadowrendertotexture", 0 ); // Turn off RTT shadows
  628. ApplyChangesToConVar( "r_flashlightdepthtexture", 0 ); // Turn off shadow depth textures
  629. }
  630. else if ( m_pShadowDetail->GetActiveItem() == 1 ) // RTT shadows only
  631. {
  632. ApplyChangesToConVar( "r_shadowrendertotexture", 1 ); // Turn on RTT shadows
  633. ApplyChangesToConVar( "r_flashlightdepthtexture", 0 ); // Turn off shadow depth textures
  634. }
  635. else if ( m_pShadowDetail->GetActiveItem() == 2 ) // Shadow depth textures
  636. {
  637. ApplyChangesToConVar( "r_shadowrendertotexture", 1 ); // Turn on RTT shadows
  638. ApplyChangesToConVar( "r_flashlightdepthtexture", 1 ); // Turn on shadow depth textures
  639. }
  640. ApplyChangesToConVar( "mat_reducefillrate", ( m_pShaderDetail->GetActiveItem() > 0 ) ? 0 : 1 );
  641. switch ( m_pWaterDetail->GetActiveItem() )
  642. {
  643. default:
  644. case 0:
  645. #ifndef _X360
  646. ApplyChangesToConVar( "r_waterforceexpensive", false );
  647. #endif
  648. ApplyChangesToConVar( "r_waterforcereflectentities", false );
  649. break;
  650. case 1:
  651. #ifndef _X360
  652. ApplyChangesToConVar( "r_waterforceexpensive", true );
  653. #endif
  654. ApplyChangesToConVar( "r_waterforcereflectentities", false );
  655. break;
  656. case 2:
  657. #ifndef _X360
  658. ApplyChangesToConVar( "r_waterforceexpensive", true );
  659. #endif
  660. ApplyChangesToConVar( "r_waterforcereflectentities", true );
  661. break;
  662. }
  663. ApplyChangesToConVar( "mat_vsync", m_pVSync->GetActiveItem() );
  664. int iMC = m_pMulticore->GetActiveItem();
  665. ApplyChangesToConVar( "mat_queue_mode", (iMC == 0) ? 0 : -1 );
  666. ApplyChangesToConVar( "mat_colorcorrection", m_pColorCorrection->GetActiveItem() );
  667. ApplyChangesToConVar( "mat_motion_blur_enabled", m_pMotionBlur->GetActiveItem() );
  668. CCvarSlider *pFOV = (CCvarSlider *)FindChildByName( "FOVSlider" );
  669. if ( pFOV )
  670. {
  671. pFOV->ApplyChanges();
  672. }
  673. }
  674. virtual void OnResetData()
  675. {
  676. ConVarRef mat_dxlevel( "mat_dxlevel" );
  677. ConVarRef r_rootlod( "r_rootlod" );
  678. ConVarRef mat_picmip( "mat_picmip" );
  679. ConVarRef mat_trilinear( "mat_trilinear" );
  680. ConVarRef mat_forceaniso( "mat_forceaniso" );
  681. ConVarRef mat_antialias( "mat_antialias" );
  682. ConVarRef mat_aaquality( "mat_aaquality" );
  683. ConVarRef mat_vsync( "mat_vsync" );
  684. ConVarRef mat_queue_mode( "mat_queue_mode" );
  685. ConVarRef r_flashlightdepthtexture( "r_flashlightdepthtexture" );
  686. #ifndef _X360
  687. ConVarRef r_waterforceexpensive( "r_waterforceexpensive" );
  688. #endif
  689. ConVarRef r_waterforcereflectentities( "r_waterforcereflectentities" );
  690. ConVarRef mat_reducefillrate("mat_reducefillrate" );
  691. ConVarRef mat_hdr_level( "mat_hdr_level" );
  692. ConVarRef mat_colorcorrection( "mat_colorcorrection" );
  693. ConVarRef mat_motion_blur_enabled( "mat_motion_blur_enabled" );
  694. ConVarRef r_shadowrendertotexture( "r_shadowrendertotexture" );
  695. ResetDXLevelCombo();
  696. m_pModelDetail->ActivateItem( 2 - clamp(r_rootlod.GetInt(), 0, 2) );
  697. m_pTextureDetail->ActivateItem( 2 - clamp(mat_picmip.GetInt(), -1, 2) );
  698. if ( r_flashlightdepthtexture.GetBool() ) // If we're doing flashlight shadow depth texturing...
  699. {
  700. r_shadowrendertotexture.SetValue( 1 ); // ...be sure render to texture shadows are also on
  701. m_pShadowDetail->ActivateItem( 2 );
  702. }
  703. else if ( r_shadowrendertotexture.GetBool() ) // RTT shadows, but not shadow depth texturing
  704. {
  705. m_pShadowDetail->ActivateItem( 1 );
  706. }
  707. else // Lowest shadow quality
  708. {
  709. m_pShadowDetail->ActivateItem( 0 );
  710. }
  711. m_pShaderDetail->ActivateItem( mat_reducefillrate.GetBool() ? 0 : 1 );
  712. m_pHDR->ActivateItem(clamp(mat_hdr_level.GetInt(), 0, 2));
  713. switch (mat_forceaniso.GetInt())
  714. {
  715. case 2:
  716. m_pFilteringMode->ActivateItem( 2 );
  717. break;
  718. case 4:
  719. m_pFilteringMode->ActivateItem( 3 );
  720. break;
  721. case 8:
  722. m_pFilteringMode->ActivateItem( 4 );
  723. break;
  724. case 16:
  725. m_pFilteringMode->ActivateItem( 5 );
  726. break;
  727. case 0:
  728. default:
  729. if (mat_trilinear.GetBool())
  730. {
  731. m_pFilteringMode->ActivateItem( 1 );
  732. }
  733. else
  734. {
  735. m_pFilteringMode->ActivateItem( 0 );
  736. }
  737. break;
  738. }
  739. // Map convar to item on AA drop-down
  740. int nAASamples = mat_antialias.GetInt();
  741. int nAAQuality = mat_aaquality.GetInt();
  742. int nMSAAMode = FindMSAAMode( nAASamples, nAAQuality );
  743. m_pAntialiasingMode->ActivateItem( nMSAAMode );
  744. m_pAntialiasingMode->SetEnabled( m_nNumAAModes > 1 );
  745. #ifndef _X360
  746. if ( r_waterforceexpensive.GetBool() )
  747. #endif
  748. {
  749. if ( r_waterforcereflectentities.GetBool() )
  750. {
  751. m_pWaterDetail->ActivateItem( 2 );
  752. }
  753. else
  754. {
  755. m_pWaterDetail->ActivateItem( 1 );
  756. }
  757. }
  758. #ifndef _X360
  759. else
  760. {
  761. m_pWaterDetail->ActivateItem( 0 );
  762. }
  763. #endif
  764. m_pVSync->ActivateItem( mat_vsync.GetInt() );
  765. int iMC = mat_queue_mode.GetInt();
  766. // We (Rick!) have now switched -2 to mean enabled. So this comment has been rendered obsolete:
  767. // -- For testing, we have -2, the legacy default setting as meaning multicore is disabled.
  768. // -- After that, we'll switch -2 to mean it's enabled.
  769. m_pMulticore->ActivateItem( (iMC == 0) ? 0 : 1 );
  770. m_pColorCorrection->ActivateItem( mat_colorcorrection.GetInt() );
  771. m_pMotionBlur->ActivateItem( mat_motion_blur_enabled.GetInt() );
  772. // get current hardware dx support level
  773. char dxVer[64];
  774. GetNameForDXLevel( mat_dxlevel.GetInt(), dxVer, sizeof( dxVer ) );
  775. SetControlString("dxlabel", dxVer);
  776. // get installed version
  777. char szVersion[64];
  778. szVersion[0] = 0;
  779. system()->GetRegistryString( "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\DirectX\\Version", szVersion, sizeof(szVersion) );
  780. int os = 0, majorVersion = 0, minorVersion = 0, subVersion = 0;
  781. sscanf(szVersion, "%d.%d.%d.%d", &os, &majorVersion, &minorVersion, &subVersion);
  782. Q_snprintf(dxVer, sizeof(dxVer), "DirectX v%d.%d", majorVersion, minorVersion);
  783. SetControlString("dxinstalledlabel", dxVer);
  784. }
  785. virtual void OnCommand( const char *command )
  786. {
  787. if ( !stricmp(command, "OK") )
  788. {
  789. if ( RequiresRestart() )
  790. {
  791. // Bring up the confirmation dialog
  792. QueryBox *box = new QueryBox("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info");
  793. box->AddActionSignalTarget( this );
  794. box->SetOKCommand(new KeyValues("OK_Confirmed"));
  795. box->SetCancelCommand(new KeyValues("ResetDXLevelCombo"));
  796. box->DoModal();
  797. box->MoveToFront();
  798. return;
  799. }
  800. m_bUseChanges = true;
  801. Close();
  802. }
  803. else
  804. {
  805. BaseClass::OnCommand( command );
  806. }
  807. }
  808. void OnKeyCodeTyped(KeyCode code)
  809. {
  810. // force ourselves to be closed if the escape key it pressed
  811. if (code == KEY_ESCAPE)
  812. {
  813. Close();
  814. }
  815. else
  816. {
  817. BaseClass::OnKeyCodeTyped(code);
  818. }
  819. }
  820. bool RequiresRestart()
  821. {
  822. if ( GameUI().IsInLevel() )
  823. {
  824. if ( GameUI().IsInBackgroundLevel() )
  825. return false;
  826. if ( !GameUI().IsInMultiplayer() )
  827. return false;
  828. ConVarRef mat_dxlevel( "mat_dxlevel" );
  829. KeyValues *pUserData = m_pDXLevel->GetActiveItemUserData();
  830. Assert( pUserData );
  831. if ( pUserData && mat_dxlevel.GetInt() != pUserData->GetInt("dxlevel") )
  832. {
  833. return true;
  834. }
  835. // HDR changed?
  836. if ( m_pHDR->IsEnabled() )
  837. {
  838. ConVarRef mat_hdr_level("mat_hdr_level");
  839. Assert( mat_hdr_level.IsValid() );
  840. if ( mat_hdr_level.GetInt() != m_pHDR->GetActiveItem() )
  841. return true;
  842. }
  843. }
  844. return false;
  845. }
  846. private:
  847. bool m_bUseChanges;
  848. vgui::ComboBox *m_pModelDetail, *m_pTextureDetail, *m_pAntialiasingMode, *m_pFilteringMode;
  849. vgui::ComboBox *m_pShadowDetail, *m_pHDR, *m_pWaterDetail, *m_pVSync, *m_pMulticore, *m_pShaderDetail;
  850. vgui::ComboBox *m_pColorCorrection;
  851. vgui::ComboBox *m_pMotionBlur;
  852. vgui::ComboBox *m_pDXLevel;
  853. int m_nNumAAModes;
  854. AAMode_t m_nAAModes[16];
  855. };
  856. #if defined( USE_SDL )
  857. //-----------------------------------------------------------------------------
  858. // Purpose: Get display index we will go fullscreen on.
  859. //-----------------------------------------------------------------------------
  860. static int getSDLDisplayIndex()
  861. {
  862. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  863. Assert( sdl_displayindex.IsValid() );
  864. return sdl_displayindex.IsValid() ? sdl_displayindex.GetInt() : 0;
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose: Get display index we are currently fullscreen on. (or -1 if none).
  868. //-----------------------------------------------------------------------------
  869. static int getSDLDisplayIndexFullscreen()
  870. {
  871. static ConVarRef sdl_displayindex_fullscreen( "sdl_displayindex_fullscreen" );
  872. Assert( sdl_displayindex_fullscreen.IsValid() );
  873. return sdl_displayindex_fullscreen.IsValid() ? sdl_displayindex_fullscreen.GetInt() : -1;
  874. }
  875. #endif // USE_SDL
  876. //-----------------------------------------------------------------------------
  877. // Purpose:
  878. //-----------------------------------------------------------------------------
  879. COptionsSubVideo::COptionsSubVideo(vgui::Panel *parent) : PropertyPage(parent, NULL)
  880. {
  881. m_bRequireRestart = false;
  882. m_bDisplayedVRModeMessage = false;
  883. m_pGammaButton = new Button( this, "GammaButton", "#GameUI_AdjustGamma" );
  884. m_pGammaButton->SetCommand(new KeyValues("OpenGammaDialog"));
  885. m_pMode = new ComboBox(this, "Resolution", 8, false);
  886. m_pAspectRatio = new ComboBox( this, "AspectRatio", 6, false );
  887. m_pVRMode = new ComboBox( this, "VRMode", 2, false );
  888. m_pAdvanced = new Button( this, "AdvancedButton", "#GameUI_AdvancedEllipsis" );
  889. m_pAdvanced->SetCommand(new KeyValues("OpenAdvanced"));
  890. m_pBenchmark = new Button( this, "BenchmarkButton", "#GameUI_LaunchBenchmark" );
  891. m_pBenchmark->SetCommand(new KeyValues("LaunchBenchmark"));
  892. m_pThirdPartyCredits = new URLButton(this, "ThirdPartyVideoCredits", "#GameUI_ThirdPartyTechCredits");
  893. m_pThirdPartyCredits->SetCommand(new KeyValues("OpenThirdPartyVideoCreditsDialog"));
  894. m_pHDContent = new CheckButton( this, "HDContentButton", "#GameUI_HDContent" );
  895. char pszAspectName[3][64];
  896. const wchar_t *unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectNormal");
  897. g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[0], 32);
  898. unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectWide16x9");
  899. g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[1], 32);
  900. unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectWide16x10");
  901. g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[2], 32);
  902. int iNormalItemID = m_pAspectRatio->AddItem( pszAspectName[0], NULL );
  903. int i16x9ItemID = m_pAspectRatio->AddItem( pszAspectName[1], NULL );
  904. int i16x10ItemID = m_pAspectRatio->AddItem( pszAspectName[2], NULL );
  905. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  906. int iAspectMode = GetScreenAspectMode( config.m_VideoMode.m_Width, config.m_VideoMode.m_Height );
  907. switch ( iAspectMode )
  908. {
  909. default:
  910. case 0:
  911. m_pAspectRatio->ActivateItem( iNormalItemID );
  912. break;
  913. case 1:
  914. m_pAspectRatio->ActivateItem( i16x9ItemID );
  915. break;
  916. case 2:
  917. m_pAspectRatio->ActivateItem( i16x10ItemID );
  918. break;
  919. }
  920. char pszVRModeName[2][64];
  921. unicodeText = g_pVGuiLocalize->Find("#GameUI_Disabled");
  922. g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszVRModeName[0], 32);
  923. unicodeText = g_pVGuiLocalize->Find("#GameUI_Enabled");
  924. g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszVRModeName[1], 32);
  925. m_pVRMode->AddItem( pszVRModeName[0], NULL );
  926. m_pVRMode->AddItem( pszVRModeName[1], NULL );
  927. // Multimonitor under Direct3D requires you to destroy and recreate the device,
  928. // which is an operation we don't support as it currently stands. The user can
  929. // pass -adapter N to use a different device.
  930. #if defined( USE_SDL ) && defined( DX_TO_GL_ABSTRACTION )
  931. int numVideoDisplays = SDL_GetNumVideoDisplays();
  932. m_pWindowed = new vgui::ComboBox( this, "DisplayModeCombo", 5 + numVideoDisplays, false );
  933. if ( numVideoDisplays <= 1 )
  934. {
  935. m_pWindowed->AddItem( "#GameUI_Fullscreen", NULL );
  936. m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
  937. }
  938. else
  939. {
  940. // Add something like this:
  941. // Full Screen (0)
  942. // Full Screen (1)
  943. // Windowed
  944. wchar_t *fullscreenText = g_pVGuiLocalize->Find( "#GameUI_Fullscreen" );
  945. for ( int i = 0; i < numVideoDisplays; i++ )
  946. {
  947. wchar_t ItemText[ 256 ];
  948. V_swprintf_safe( ItemText, L"%ls (%d)", fullscreenText, i );
  949. m_pWindowed->AddItem( ItemText, NULL );
  950. }
  951. m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
  952. }
  953. #else
  954. m_pWindowed = new vgui::ComboBox( this, "DisplayModeCombo", 6, false );
  955. m_pWindowed->AddItem( "#GameUI_Fullscreen", NULL );
  956. m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
  957. #endif
  958. LoadControlSettings("Resource\\OptionsSubVideo.res");
  959. // Moved down here so we can set the Drop down's
  960. // menu state after the default (disabled) value is loaded
  961. PrepareResolutionList();
  962. // only show the benchmark button if they have the benchmark map
  963. if ( !g_pFullFileSystem->FileExists("maps/test_hardware.bsp") )
  964. {
  965. m_pBenchmark->SetVisible( false );
  966. }
  967. if ( ModInfo().HasHDContent() )
  968. {
  969. m_pHDContent->SetVisible( true );
  970. }
  971. // if VR mode isn't available, disable the dropdown
  972. if( !g_pSourceVR )
  973. {
  974. // if sourcevr.dll is missing entirely that means VR mode is not
  975. // supported in this game. Hide the mode dropdown and its label
  976. m_pVRMode->SetVisible( false );
  977. Panel *label = FindChildByName( "VRModeLabel" );
  978. if( label )
  979. label->SetVisible( false );
  980. }
  981. else if( !g_pSourceVR->IsHmdConnected() )
  982. {
  983. m_pVRMode->ActivateItem( 0 );
  984. m_pVRMode->SetEnabled( false );
  985. m_pVRMode->GetTooltip()->SetText( "#GameUI_NoVRTooltip" );
  986. EnableOrDisableWindowedForVR();
  987. }
  988. }
  989. //-----------------------------------------------------------------------------
  990. // Purpose: Generates resolution list
  991. //-----------------------------------------------------------------------------
  992. void COptionsSubVideo::PrepareResolutionList()
  993. {
  994. // get the currently selected resolution
  995. char sz[256];
  996. m_pMode->GetText(sz, 256);
  997. int currentWidth = 0, currentHeight = 0;
  998. sscanf( sz, "%i x %i", &currentWidth, &currentHeight );
  999. // Clean up before filling the info again.
  1000. m_pMode->DeleteAllItems();
  1001. m_pAspectRatio->SetItemEnabled(1, false);
  1002. m_pAspectRatio->SetItemEnabled(2, false);
  1003. // get full video mode list
  1004. vmode_t *plist = NULL;
  1005. int count = 0;
  1006. gameuifuncs->GetVideoModes( &plist, &count );
  1007. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1008. // Windowed is the last item in the combobox.
  1009. bool bWindowed = ( m_pWindowed->GetActiveItem() >= ( m_pWindowed->GetItemCount() - 1 ) );
  1010. int desktopWidth, desktopHeight;
  1011. gameuifuncs->GetDesktopResolution( desktopWidth, desktopHeight );
  1012. #if defined( USE_SDL )
  1013. bool bFullScreenWithMultipleDisplays = ( !bWindowed && ( SDL_GetNumVideoDisplays() > 1 ) );
  1014. if ( bFullScreenWithMultipleDisplays )
  1015. {
  1016. SDL_Rect rect;
  1017. #if defined( DX_TO_GL_ABSTRACTION )
  1018. int displayIndex = m_pWindowed->GetActiveItem();
  1019. #else
  1020. int displayIndex = materials->GetCurrentAdapter();
  1021. #endif
  1022. if ( !SDL_GetDisplayBounds( displayIndex, &rect ) )
  1023. {
  1024. desktopWidth = rect.w;
  1025. desktopHeight = rect.h;
  1026. }
  1027. }
  1028. // If we are switching to fullscreen, and this isn't the mode we're currently in, then
  1029. // fake things out so the native fullscreen resolution is selected. Stuck this in
  1030. // because I assume most people will go fullscreen at native resolution, and it's sometimes
  1031. // difficult to find the native resolution with all the aspect ratio options.
  1032. bool bNewFullscreenDisplay = ( !bWindowed && ( getSDLDisplayIndexFullscreen() != m_pWindowed->GetActiveItem() ) );
  1033. if ( bNewFullscreenDisplay )
  1034. {
  1035. currentWidth = desktopWidth;
  1036. currentHeight = desktopHeight;
  1037. }
  1038. #endif
  1039. // iterate all the video modes adding them to the dropdown
  1040. bool bFoundWidescreen = false;
  1041. int selectedItemID = -1;
  1042. for (int i = 0; i < count; i++, plist++)
  1043. {
  1044. #if !defined( USE_SDL )
  1045. // don't show modes bigger than the desktop for windowed mode
  1046. if ( bWindowed )
  1047. #endif
  1048. {
  1049. if ( plist->width > desktopWidth || plist->height > desktopHeight )
  1050. {
  1051. // Filter out sizes larger than our desktop.
  1052. continue;
  1053. }
  1054. }
  1055. GetResolutionName( plist, sz, sizeof( sz ), desktopWidth, desktopHeight );
  1056. int itemID = -1;
  1057. int iAspectMode = GetScreenAspectMode( plist->width, plist->height );
  1058. if ( iAspectMode > 0 )
  1059. {
  1060. m_pAspectRatio->SetItemEnabled( iAspectMode, true );
  1061. bFoundWidescreen = true;
  1062. }
  1063. // filter the list for those matching the current aspect
  1064. if ( iAspectMode == m_pAspectRatio->GetActiveItem() )
  1065. {
  1066. itemID = m_pMode->AddItem( sz, NULL);
  1067. }
  1068. // try and find the best match for the resolution to be selected
  1069. if ( plist->width == currentWidth && plist->height == currentHeight )
  1070. {
  1071. selectedItemID = itemID;
  1072. }
  1073. else if ( selectedItemID == -1 && plist->width == config.m_VideoMode.m_Width && plist->height == config.m_VideoMode.m_Height )
  1074. {
  1075. selectedItemID = itemID;
  1076. }
  1077. }
  1078. // disable ratio selection if we can't display widescreen.
  1079. m_pAspectRatio->SetEnabled( bFoundWidescreen );
  1080. m_nSelectedMode = selectedItemID;
  1081. if ( selectedItemID != -1 )
  1082. {
  1083. m_pMode->ActivateItem( selectedItemID );
  1084. }
  1085. else
  1086. {
  1087. int Width = config.m_VideoMode.m_Width;
  1088. int Height = config.m_VideoMode.m_Height;
  1089. #if defined( USE_SDL )
  1090. // If we are switching to a new display, or the size is greater than the desktop, then
  1091. // display the desktop width and height.
  1092. if ( bNewFullscreenDisplay || ( Width > desktopWidth ) || ( Height > desktopHeight ) )
  1093. {
  1094. Width = desktopWidth;
  1095. Height = desktopHeight;
  1096. }
  1097. #endif
  1098. Q_snprintf( sz, ARRAYSIZE( sz ), "%d x %d", Width, Height );
  1099. m_pMode->SetText( sz );
  1100. }
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose:
  1104. //-----------------------------------------------------------------------------
  1105. COptionsSubVideo::~COptionsSubVideo()
  1106. {
  1107. if (m_hOptionsSubVideoAdvancedDlg.Get())
  1108. {
  1109. m_hOptionsSubVideoAdvancedDlg->MarkForDeletion();
  1110. }
  1111. }
  1112. FILE *FOpenGameHDFile( const char *pchMode )
  1113. {
  1114. const char *pGameDir = engine->GetGameDirectory();
  1115. char szModSteamInfPath[ 1024 ];
  1116. V_ComposeFileName( pGameDir, "game_hd.txt", szModSteamInfPath, sizeof( szModSteamInfPath ) );
  1117. FILE *fp = fopen( szModSteamInfPath, pchMode );
  1118. return fp;
  1119. }
  1120. //-----------------------------------------------------------------------------
  1121. // Purpose:
  1122. //-----------------------------------------------------------------------------
  1123. bool COptionsSubVideo::BUseHDContent()
  1124. {
  1125. FILE *fp = FOpenGameHDFile( "rb" );
  1126. if ( fp )
  1127. {
  1128. fclose(fp);
  1129. return true;
  1130. }
  1131. return false;
  1132. }
  1133. //-----------------------------------------------------------------------------
  1134. // Purpose: hint the engine to load HD content if possible, logic must match with engine/common.cpp BLoadHDContent
  1135. //-----------------------------------------------------------------------------
  1136. void COptionsSubVideo::SetUseHDContent( bool bUse )
  1137. {
  1138. if ( bUse )
  1139. {
  1140. FILE *fp = FOpenGameHDFile( "wb+" );
  1141. if ( fp )
  1142. {
  1143. fprintf( fp, "If this file exists on disk HD content will be loaded.\n" );
  1144. fclose( fp );
  1145. }
  1146. }
  1147. else
  1148. {
  1149. const char *pGameDir = engine->GetGameDirectory();
  1150. char szModSteamInfPath[ 1024 ];
  1151. V_ComposeFileName( pGameDir, "game_hd.txt", szModSteamInfPath, sizeof( szModSteamInfPath ) );
  1152. _unlink( szModSteamInfPath );
  1153. }
  1154. }
  1155. //-----------------------------------------------------------------------------
  1156. // Purpose:
  1157. //-----------------------------------------------------------------------------
  1158. void COptionsSubVideo::OnResetData()
  1159. {
  1160. m_bRequireRestart = false;
  1161. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1162. // reset UI elements
  1163. #if defined( USE_SDL ) && defined( DX_TO_GL_ABSTRACTION )
  1164. int ItemIndex;
  1165. if ( config.Windowed() )
  1166. {
  1167. // Last item in the combobox is Windowed.
  1168. ItemIndex = ( m_pWindowed->GetItemCount() - 1 );
  1169. }
  1170. else
  1171. {
  1172. // Check which fullscreen displayindex is currently selected, and pick it.
  1173. ItemIndex = getSDLDisplayIndex();
  1174. if ( ( ItemIndex < 0 ) || ItemIndex >= ( m_pWindowed->GetItemCount() - 1 ) )
  1175. {
  1176. Assert( 0 );
  1177. ItemIndex = 0;
  1178. }
  1179. }
  1180. m_pWindowed->ActivateItem( ItemIndex );
  1181. #else
  1182. m_pWindowed->ActivateItem( config.Windowed() ? 1 : 0 );
  1183. #endif
  1184. // reset gamma control
  1185. m_pGammaButton->SetEnabled( !config.Windowed() );
  1186. m_pHDContent->SetSelected( BUseHDContent() );
  1187. SetCurrentResolutionComboItem();
  1188. bool bVREnabled = config.m_nVRModeAdapter != -1;
  1189. m_pVRMode->ActivateItem( bVREnabled ? 1 : 0 );
  1190. EnableOrDisableWindowedForVR();
  1191. }
  1192. //-----------------------------------------------------------------------------
  1193. // Purpose:
  1194. //-----------------------------------------------------------------------------
  1195. void COptionsSubVideo::SetCurrentResolutionComboItem()
  1196. {
  1197. vmode_t *plist = NULL;
  1198. int count = 0;
  1199. gameuifuncs->GetVideoModes( &plist, &count );
  1200. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1201. int resolution = -1;
  1202. for ( int i = 0; i < count; i++, plist++ )
  1203. {
  1204. if ( plist->width == config.m_VideoMode.m_Width &&
  1205. plist->height == config.m_VideoMode.m_Height )
  1206. {
  1207. resolution = i;
  1208. break;
  1209. }
  1210. }
  1211. if (resolution != -1)
  1212. {
  1213. char sz[256];
  1214. int desktopWidth, desktopHeight;
  1215. gameuifuncs->GetDesktopResolution( desktopWidth, desktopHeight );
  1216. #if defined( USE_SDL )
  1217. SDL_Rect rect;
  1218. #if defined( DX_TO_GL_ABSTRACTION )
  1219. int displayIndex = getSDLDisplayIndex();
  1220. #else
  1221. int displayIndex = materials->GetCurrentAdapter();
  1222. #endif
  1223. if ( !SDL_GetDisplayBounds( displayIndex, &rect ) )
  1224. {
  1225. desktopWidth = rect.w;
  1226. desktopHeight = rect.h;
  1227. }
  1228. #endif
  1229. GetResolutionName( plist, sz, sizeof(sz), desktopWidth, desktopHeight );
  1230. m_pMode->SetText(sz);
  1231. }
  1232. }
  1233. //-----------------------------------------------------------------------------
  1234. // Purpose: restarts the game
  1235. //-----------------------------------------------------------------------------
  1236. void COptionsSubVideo::OnApplyChanges()
  1237. {
  1238. if ( RequiresRestart() )
  1239. {
  1240. INetChannelInfo *nci = engine->GetNetChannelInfo();
  1241. if ( nci )
  1242. {
  1243. // Only retry if we're not running the server
  1244. const char *pAddr = nci->GetAddress();
  1245. if ( pAddr )
  1246. {
  1247. if ( Q_strncmp(pAddr,"127.0.0.1",9) && Q_strncmp(pAddr,"localhost",9) )
  1248. {
  1249. engine->ClientCmd_Unrestricted( "retry\n" );
  1250. }
  1251. else
  1252. {
  1253. engine->ClientCmd_Unrestricted( "disconnect\n" );
  1254. }
  1255. }
  1256. }
  1257. }
  1258. // apply advanced options
  1259. if (m_hOptionsSubVideoAdvancedDlg.Get())
  1260. {
  1261. m_hOptionsSubVideoAdvancedDlg->ApplyChanges();
  1262. }
  1263. // resolution
  1264. char sz[256];
  1265. if ( m_nSelectedMode == -1 )
  1266. {
  1267. m_pMode->GetText( sz, 256 );
  1268. }
  1269. else
  1270. {
  1271. m_pMode->GetItemText( m_nSelectedMode, sz, 256 );
  1272. }
  1273. int width = 0, height = 0;
  1274. sscanf( sz, "%i x %i", &width, &height );
  1275. // windowed
  1276. bool bConfigChanged = false;
  1277. bool windowed = ( m_pWindowed->GetActiveItem() == ( m_pWindowed->GetItemCount() - 1 ) ) ? true : false;
  1278. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1279. bool bVRMode = m_pVRMode->GetActiveItem() != 0;
  1280. if( ( -1 != config.m_nVRModeAdapter ) != bVRMode )
  1281. {
  1282. // let engine fill in mat_vrmode_adapter
  1283. char szCmd[256];
  1284. Q_snprintf( szCmd, sizeof(szCmd), "mat_enable_vrmode %d\n", bVRMode ? 1 : 0 );
  1285. engine->ClientCmd_Unrestricted( szCmd );
  1286. // force windowed. VR mode ignores this flag and desktop mode needs to be in a window always
  1287. windowed = bVRMode;
  1288. }
  1289. // make sure there is a change
  1290. if ( config.m_VideoMode.m_Width != width
  1291. || config.m_VideoMode.m_Height != height
  1292. || config.Windowed() != windowed )
  1293. {
  1294. bConfigChanged = true;
  1295. }
  1296. #if defined( USE_SDL )
  1297. if ( !windowed )
  1298. {
  1299. SDL_Rect rect;
  1300. int displayIndexTarget = m_pWindowed->GetActiveItem();
  1301. int displayIndexCurrent = getSDLDisplayIndexFullscreen();
  1302. // Handle going fullscreen from display X to display Y.
  1303. if ( displayIndexCurrent != displayIndexTarget )
  1304. {
  1305. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  1306. if ( sdl_displayindex.IsValid() )
  1307. {
  1308. // Set the displayindex we want to go fullscreen on now.
  1309. sdl_displayindex.SetValue( displayIndexTarget );
  1310. bConfigChanged = true;
  1311. }
  1312. }
  1313. if ( !SDL_GetDisplayBounds( displayIndexTarget, &rect ) )
  1314. {
  1315. // If we are going non-native fullscreen, tweak the resolution to have the same aspect ratio as the display.
  1316. if ( ( width != rect.w ) || ( height != rect.h ) )
  1317. {
  1318. // TODO: We may want a convar to allow folks to mess with their aspect ratio?
  1319. height = ( width * rect.h ) / rect.w;
  1320. bConfigChanged = true;
  1321. }
  1322. }
  1323. }
  1324. #endif // USE_SDL
  1325. if ( bConfigChanged )
  1326. {
  1327. // set mode
  1328. char szCmd[ 256 ];
  1329. Q_snprintf( szCmd, sizeof( szCmd ), "mat_setvideomode %i %i %i\n", width, height, windowed ? 1 : 0 );
  1330. engine->ClientCmd_Unrestricted( szCmd );
  1331. }
  1332. if ( ModInfo().HasHDContent() )
  1333. {
  1334. if ( BUseHDContent() != m_pHDContent->IsSelected() )
  1335. {
  1336. SetUseHDContent( m_pHDContent->IsSelected() );
  1337. // Bring up the confirmation dialog
  1338. MessageBox *box = new MessageBox("#GameUI_OptionsRestartRequired_Title", "#GameUI_HDRestartRequired_Info");
  1339. box->DoModal();
  1340. box->MoveToFront();
  1341. }
  1342. }
  1343. // apply changes
  1344. engine->ClientCmd_Unrestricted( "mat_savechanges\n" );
  1345. }
  1346. //-----------------------------------------------------------------------------
  1347. // Purpose:
  1348. //-----------------------------------------------------------------------------
  1349. void COptionsSubVideo::PerformLayout()
  1350. {
  1351. BaseClass::PerformLayout();
  1352. if ( m_pGammaButton )
  1353. {
  1354. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1355. m_pGammaButton->SetEnabled( !config.Windowed() );
  1356. }
  1357. }
  1358. //-----------------------------------------------------------------------------
  1359. // Purpose: enables apply button on data changing
  1360. //-----------------------------------------------------------------------------
  1361. void COptionsSubVideo::OnTextChanged(Panel *pPanel, const char *pszText)
  1362. {
  1363. if (pPanel == m_pMode)
  1364. {
  1365. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  1366. m_nSelectedMode = m_pMode->GetActiveItem();
  1367. int w = 0, h = 0;
  1368. sscanf(pszText, "%i x %i", &w, &h);
  1369. if ( config.m_VideoMode.m_Width != w || config.m_VideoMode.m_Height != h )
  1370. {
  1371. OnDataChanged();
  1372. }
  1373. }
  1374. else if (pPanel == m_pAspectRatio)
  1375. {
  1376. PrepareResolutionList();
  1377. }
  1378. else if (pPanel == m_pWindowed)
  1379. {
  1380. PrepareResolutionList();
  1381. OnDataChanged();
  1382. }
  1383. else if ( pPanel == m_pVRMode )
  1384. {
  1385. if ( !m_bDisplayedVRModeMessage )
  1386. {
  1387. bool bVRNowEnabled = m_pVRMode->GetActiveItem() == 1;
  1388. bool bVRWasEnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter != -1;
  1389. if( bVRWasEnabled != bVRNowEnabled )
  1390. {
  1391. m_bDisplayedVRModeMessage = true;
  1392. MessageBox *box = new MessageBox( "#GameUI_VRMode", "#GameUI_VRModeRelaunchMsg", this );
  1393. box->MoveToFront();
  1394. box->DoModal();
  1395. }
  1396. }
  1397. EnableOrDisableWindowedForVR();
  1398. }
  1399. }
  1400. //-----------------------------------------------------------------------------
  1401. // Purpose: enables windowed combo box
  1402. //-----------------------------------------------------------------------------
  1403. void COptionsSubVideo::EnableOrDisableWindowedForVR()
  1404. {
  1405. bool bCanBeEnabled = g_pSourceVR && g_pSourceVR->IsHmdConnected();
  1406. bool bVRNowEnabled = m_pVRMode->GetActiveItem() == 1;
  1407. bool bVRWasEnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter != -1;
  1408. if( bCanBeEnabled && ( bVRNowEnabled || bVRWasEnabled ) )
  1409. {
  1410. m_pWindowed->SetEnabled( false );
  1411. m_pWindowed->ActivateItem( m_pWindowed->GetItemCount() - 1 );
  1412. m_pWindowed->GetTooltip()->SetText( "#GameUI_WindowedTooltip" );
  1413. }
  1414. else
  1415. {
  1416. m_pWindowed->SetEnabled( true );
  1417. }
  1418. }
  1419. //-----------------------------------------------------------------------------
  1420. // Purpose: enables apply button
  1421. //-----------------------------------------------------------------------------
  1422. void COptionsSubVideo::OnDataChanged()
  1423. {
  1424. PostActionSignal(new KeyValues("ApplyButtonEnable"));
  1425. }
  1426. //-----------------------------------------------------------------------------
  1427. // Purpose: Checks to see if the changes requires a restart to take effect
  1428. //-----------------------------------------------------------------------------
  1429. bool COptionsSubVideo::RequiresRestart()
  1430. {
  1431. if ( m_hOptionsSubVideoAdvancedDlg.Get()
  1432. && m_hOptionsSubVideoAdvancedDlg->RequiresRestart() )
  1433. {
  1434. return true;
  1435. }
  1436. // make sure there is a change
  1437. return m_bRequireRestart;
  1438. }
  1439. //-----------------------------------------------------------------------------
  1440. // Purpose: Opens advanced video mode options dialog
  1441. //-----------------------------------------------------------------------------
  1442. void COptionsSubVideo::OpenAdvanced()
  1443. {
  1444. if ( !m_hOptionsSubVideoAdvancedDlg.Get() )
  1445. {
  1446. m_hOptionsSubVideoAdvancedDlg = new COptionsSubVideoAdvancedDlg( BasePanel()->FindChildByName( "OptionsDialog" ) ); // we'll parent this to the OptionsDialog directly
  1447. }
  1448. m_hOptionsSubVideoAdvancedDlg->Activate();
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Purpose: Opens gamma-adjusting dialog
  1452. //-----------------------------------------------------------------------------
  1453. void COptionsSubVideo::OpenGammaDialog()
  1454. {
  1455. if ( !m_hGammaDialog.Get() )
  1456. {
  1457. m_hGammaDialog = new CGammaDialog( GetVParent() );
  1458. }
  1459. m_hGammaDialog->Activate();
  1460. }
  1461. //-----------------------------------------------------------------------------
  1462. // Purpose: Opens benchmark dialog
  1463. //-----------------------------------------------------------------------------
  1464. void COptionsSubVideo::LaunchBenchmark()
  1465. {
  1466. BasePanel()->OnOpenBenchmarkDialog();
  1467. }
  1468. //-----------------------------------------------------------------------------
  1469. // Purpose: third-party audio credits dialog
  1470. //-----------------------------------------------------------------------------
  1471. class COptionsSubVideoThirdPartyCreditsDlg : public vgui::Frame
  1472. {
  1473. DECLARE_CLASS_SIMPLE( COptionsSubVideoThirdPartyCreditsDlg, vgui::Frame );
  1474. public:
  1475. COptionsSubVideoThirdPartyCreditsDlg( vgui::VPANEL hParent ) : BaseClass( NULL, NULL )
  1476. {
  1477. // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
  1478. SetTitle("#GameUI_ThirdPartyVideo_Title", true);
  1479. SetSize( 500, 200 );
  1480. LoadControlSettings( "resource/OptionsSubVideoThirdPartyDlg.res" );
  1481. MoveToCenterOfScreen();
  1482. SetSizeable( false );
  1483. SetDeleteSelfOnClose( true );
  1484. }
  1485. virtual void Activate()
  1486. {
  1487. BaseClass::Activate();
  1488. input()->SetAppModalSurface(GetVPanel());
  1489. }
  1490. void OnKeyCodeTyped(KeyCode code)
  1491. {
  1492. // force ourselves to be closed if the escape key it pressed
  1493. if (code == KEY_ESCAPE)
  1494. {
  1495. Close();
  1496. }
  1497. else
  1498. {
  1499. BaseClass::OnKeyCodeTyped(code);
  1500. }
  1501. }
  1502. };
  1503. //-----------------------------------------------------------------------------
  1504. // Purpose: Open third party audio credits dialog
  1505. //-----------------------------------------------------------------------------
  1506. void COptionsSubVideo::OpenThirdPartyVideoCreditsDialog()
  1507. {
  1508. if (!m_OptionsSubVideoThirdPartyCreditsDlg.Get())
  1509. {
  1510. m_OptionsSubVideoThirdPartyCreditsDlg = new COptionsSubVideoThirdPartyCreditsDlg(GetVParent());
  1511. }
  1512. m_OptionsSubVideoThirdPartyCreditsDlg->Activate();
  1513. }