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.

4006 lines
146 KiB

  1. //========== Copyright (c) 2008, Valve Corporation, All rights reserved. ==========
  2. //
  3. // Purpose:
  4. //
  5. //=================================================================================
  6. #include "cbase.h"
  7. #include "materialsystem/imaterialsystem.h"
  8. #include "materialsystem/itexture.h"
  9. #include "materialsystem/imaterialvar.h"
  10. #include "materialsystem/imaterialsystemhardwareconfig.h"
  11. #include "materialsystem/materialsystem_config.h"
  12. #include "tier1/callqueue.h"
  13. #include "colorcorrectionmgr.h"
  14. #include "view_scene.h"
  15. #include "c_world.h"
  16. #include "renderparm.h"
  17. #include "shaderapi/ishaderapi.h"
  18. #include "proxyentity.h"
  19. #include "imaterialproxydict.h"
  20. #include "model_types.h"
  21. #include "bitmap/tgawriter.h"
  22. #include "filesystem.h"
  23. #ifdef PORTAL2
  24. #include "c_portal_player.h"
  25. #endif
  26. #ifdef CSTRIKE15
  27. #include "weapon_csbase.h"
  28. #include "c_cs_player.h"
  29. #endif
  30. // NOTE: This has to be the last file included!
  31. #include "tier0/memdbgon.h"
  32. //-----------------------------------------------------------------------------
  33. // Globals
  34. //-----------------------------------------------------------------------------
  35. // mapmaker controlled autoexposure
  36. bool g_bUseCustomAutoExposureMin = false;
  37. bool g_bUseCustomAutoExposureMax = false;
  38. bool g_bUseCustomBloomScale = false;
  39. float g_flCustomAutoExposureMin = 0;
  40. float g_flCustomAutoExposureMax = 0;
  41. float g_flCustomBloomScale = 0.0f;
  42. float g_flCustomBloomScaleMinimum = 0.0f;
  43. float g_flBloomExponent = 2.5f;
  44. float g_flBloomSaturation = 1.0f;
  45. float g_flTonemapPercentBrightPixels = 2.0f;
  46. float g_flTonemapMinAvgLum = 3.0f;
  47. float g_flTonemapRate = 1.0f;
  48. #if defined( _X360 )
  49. #if defined( CSTRIKE15 )
  50. float g_flTonemapPercentTarget = 60.0f;
  51. #else
  52. // Move "up" the percent target to make X360 a bit brighter than it's been to compensate for our bad 8-bit histogram utilization and to also compensate for the non-PWL texture change.
  53. float g_flTonemapPercentTarget = 80.0f
  54. #endif
  55. #else
  56. float g_flTonemapPercentTarget = 60.0f;
  57. #endif
  58. extern void GetTonemapSettingsFromEnvTonemapController( void );
  59. // mapmaker controlled depth of field
  60. bool g_bDOFEnabled = false;
  61. float g_flDOFNearBlurDepth = 50.0f;
  62. float g_flDOFNearFocusDepth = 200.0f;
  63. float g_flDOFFarFocusDepth = 250.0f;
  64. float g_flDOFFarBlurDepth = 1000.0f;
  65. float g_flDOFNearBlurRadius = 0.0f;
  66. float g_flDOFFarBlurRadius = 5.0f;
  67. bool g_bFlashlightIsOn = false;
  68. // hdr parameters
  69. ConVar mat_bloomscale( "mat_bloomscale", "1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  70. ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_DEVELOPMENTONLY );
  71. ConVar mat_bloomamount_rate( "mat_bloomamount_rate", "0.05f", FCVAR_CHEAT );
  72. static ConVar debug_postproc( "mat_debug_postprocessing_effects", "0", FCVAR_CHEAT, "0 = off, 1 = show post-processing passes in quadrants of the screen, 2 = only apply post-processing to the centre of the screen" );
  73. static ConVar mat_dynamic_tonemapping( "mat_dynamic_tonemapping", "1", FCVAR_CHEAT );
  74. static ConVar mat_tonemapping_occlusion_use_stencil( "mat_tonemapping_occlusion_use_stencil", "0", FCVAR_DEVELOPMENTONLY );
  75. static ConVar mat_autoexposure_max( "mat_autoexposure_max", "2", FCVAR_CHEAT );
  76. #if defined( _X360 )
  77. #if defined( CSTRIKE15 )
  78. static ConVar mat_autoexposure_max_multiplier("mat_autoexposure_max_multiplier","1.0", FCVAR_CHEAT);
  79. #else
  80. // Allow the max. pixel shader multiplier to be 50% higher to better utilize the available 8-bit output range, and to help compensate for the gamma ramp adjustments we've made. (At some point we should also adjust the PS3.)
  81. static ConVar mat_autoexposure_max_multiplier("mat_autoexposure_max_multiplier","1.5", FCVAR_CHEAT );
  82. #endif
  83. #else
  84. static ConVar mat_autoexposure_max_multiplier("mat_autoexposure_max_multiplier","1.0", FCVAR_CHEAT );
  85. #endif
  86. static ConVar mat_autoexposure_min( "mat_autoexposure_min", "0.5", FCVAR_CHEAT );
  87. static ConVar mat_show_histogram( "mat_show_histogram", "0", FCVAR_CHEAT );
  88. ConVar mat_hdr_uncapexposure( "mat_hdr_uncapexposure", "0", FCVAR_CHEAT );
  89. ConVar mat_force_bloom("mat_force_bloom","0", FCVAR_CHEAT );
  90. ConVar mat_disable_bloom("mat_disable_bloom","0", FCVAR_CHEAT );
  91. ConVar mat_debug_bloom("mat_debug_bloom","0", FCVAR_CHEAT);
  92. ConVar mat_colorcorrection( "mat_colorcorrection", "1", FCVAR_CHEAT );
  93. ConVar mat_accelerate_adjust_exposure_down( "mat_accelerate_adjust_exposure_down", "40.0", FCVAR_CHEAT );
  94. // fudge factor to make non-hdr bloom more closely match hdr bloom. Because of auto-exposure, high
  95. // bloomscales don't blow out as much in hdr. this factor was derived by comparing images in a
  96. // reference scene.
  97. ConVar mat_non_hdr_bloom_scalefactor("mat_non_hdr_bloom_scalefactor",".3", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  98. // Apply addition scale to the final bloom scale
  99. static ConVar mat_bloom_scalefactor_scalar( "mat_bloom_scalefactor_scalar", "1.0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  100. //ConVar mat_exposure_center_region_x( "mat_exposure_center_region_x","0.75", FCVAR_CHEAT );
  101. //ConVar mat_exposure_center_region_y( "mat_exposure_center_region_y","0.80", FCVAR_CHEAT );
  102. ConVar mat_exposure_center_region_x( "mat_exposure_center_region_x","0.9", FCVAR_CHEAT );
  103. ConVar mat_exposure_center_region_y( "mat_exposure_center_region_y","0.85", FCVAR_CHEAT );
  104. ConVar mat_tonemap_algorithm( "mat_tonemap_algorithm", "1", FCVAR_CHEAT, "0 = Original Algorithm 1 = New Algorithm" );
  105. ConVar mat_force_tonemap_percent_target( "mat_force_tonemap_percent_target", "-1", FCVAR_CHEAT, "Override. Old default was 60." );
  106. ConVar mat_force_tonemap_percent_bright_pixels( "mat_force_tonemap_percent_bright_pixels", "-1", FCVAR_CHEAT, "Override. Old value was 2.0" );
  107. ConVar mat_force_tonemap_min_avglum( "mat_force_tonemap_min_avglum", "-1", FCVAR_CHEAT, "Override. Old default was 3.0" );
  108. ConVar mat_force_tonemap_scale( "mat_force_tonemap_scale", "0.0", FCVAR_CHEAT );
  109. ConVar mat_fullbright( "mat_fullbright", "0", FCVAR_CHEAT );
  110. ConVar mat_grain_enable( "mat_grain_enable", "1" );
  111. //ConVar mat_vignette_enable( "mat_vignette_enable", "1", FCVAR_RELEASE | FCVAR_REPLICATED );
  112. ConVar mat_local_contrast_enable( "mat_local_contrast_enable", "1", FCVAR_DEVELOPMENTONLY );
  113. ConVar mat_blur_r( "mat_blur_r", "0.7" );
  114. ConVar mat_blur_g( "mat_blur_g", "0.7" );
  115. ConVar mat_blur_b( "mat_blur_b", "0.7" );
  116. #if defined(_PS3)
  117. ConVar mat_PS3_findpostvarsfast( "mat_PS3_findpostvarsfast", "1" );
  118. #endif
  119. // These material proxies + the GetXXXMaterial calls within have been added for PS3 for perf reasons (to avoid the expensive PS3 mutexes on Find_Var, Find_Material)
  120. // gives us almost 0.5ms saving from main thread, could be added to other platforms - need to test
  121. // FIXME: also need to test in and out of levels, but that is not currently working without this change on the current PS3 CS:GO build anyway
  122. //=====================================================================================================================
  123. // LumCompare material proxy ============================================================================================
  124. //=====================================================================================================================
  125. class CLumCompareMaterialProxy : public CEntityMaterialProxy
  126. {
  127. public:
  128. CLumCompareMaterialProxy();
  129. virtual ~CLumCompareMaterialProxy() {};
  130. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  131. virtual void OnBind( C_BaseEntity *pEntity );
  132. virtual IMaterial *GetMaterial();
  133. static IMaterial *GetLumCompareMaterial( IMaterialSystem * materials );
  134. static void SetupLumCompareMaterial( float flTestRangeMin, float flTestRangeMax );
  135. private:
  136. static IMaterialVar *s_pMaterialParam_C0_X;
  137. static IMaterialVar *s_pMaterialParam_C0_Y;
  138. static float s_C0_X;
  139. static float s_C0_Y;
  140. static IMaterial *s_pLumCompareMaterial;
  141. };
  142. IMaterialVar *CLumCompareMaterialProxy::s_pMaterialParam_C0_X = NULL;
  143. IMaterialVar *CLumCompareMaterialProxy::s_pMaterialParam_C0_Y = NULL;
  144. float CLumCompareMaterialProxy::s_C0_X = -1e20f;
  145. float CLumCompareMaterialProxy::s_C0_Y = 1e20f;
  146. IMaterial *CLumCompareMaterialProxy::s_pLumCompareMaterial = NULL;
  147. CLumCompareMaterialProxy::CLumCompareMaterialProxy()
  148. {
  149. s_pMaterialParam_C0_X = NULL;
  150. s_pMaterialParam_C0_Y = NULL;
  151. s_pLumCompareMaterial = NULL;
  152. }
  153. bool CLumCompareMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  154. {
  155. bool bFoundVar = false;
  156. s_pLumCompareMaterial = materials->FindMaterial( "dev/lumcompare", TEXTURE_GROUP_OTHER, true );
  157. s_pMaterialParam_C0_X = pMaterial->FindVar( "$C0_X", &bFoundVar, false );
  158. s_pMaterialParam_C0_Y = pMaterial->FindVar( "$C0_Y", &bFoundVar, false );
  159. return true;
  160. }
  161. void CLumCompareMaterialProxy::OnBind( C_BaseEntity *pEnt )
  162. {
  163. }
  164. IMaterial *CLumCompareMaterialProxy::GetMaterial()
  165. {
  166. if ( s_pMaterialParam_C0_X == NULL)
  167. return NULL;
  168. return s_pMaterialParam_C0_X->GetOwningMaterial();
  169. }
  170. IMaterial *CLumCompareMaterialProxy::GetLumCompareMaterial( IMaterialSystem * materials )
  171. {
  172. if( s_pLumCompareMaterial == NULL)
  173. {
  174. s_pLumCompareMaterial = materials->FindMaterial( "dev/lumcompare", TEXTURE_GROUP_OTHER, true );
  175. }
  176. return s_pLumCompareMaterial;
  177. }
  178. void CLumCompareMaterialProxy::SetupLumCompareMaterial( float flTestRangeMin, float flTestRangeMax )
  179. {
  180. s_C0_X = flTestRangeMin;
  181. s_C0_Y = flTestRangeMax;
  182. s_pMaterialParam_C0_X->SetFloatValue( s_C0_X );
  183. s_pMaterialParam_C0_Y->SetFloatValue( s_C0_Y );
  184. }
  185. EXPOSE_MATERIAL_PROXY( CLumCompareMaterialProxy, LumCompare );
  186. //=====================================================================================================================
  187. // LumCompareStencil material proxy ============================================================================================
  188. //=====================================================================================================================
  189. class CLumCompareStencilMaterialProxy : public CEntityMaterialProxy
  190. {
  191. public:
  192. CLumCompareStencilMaterialProxy();
  193. virtual ~CLumCompareStencilMaterialProxy() {};
  194. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  195. virtual void OnBind( C_BaseEntity *pEntity );
  196. virtual IMaterial *GetMaterial();
  197. private:
  198. public:
  199. static IMaterial *GetLumCompareStencilMaterial( IMaterialSystem * materials );
  200. private:
  201. static IMaterial *s_pLumCompareStencilMaterial;
  202. };
  203. IMaterial *CLumCompareStencilMaterialProxy::s_pLumCompareStencilMaterial = NULL;
  204. CLumCompareStencilMaterialProxy::CLumCompareStencilMaterialProxy()
  205. {
  206. s_pLumCompareStencilMaterial = NULL;
  207. }
  208. bool CLumCompareStencilMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  209. {
  210. return true;
  211. }
  212. void CLumCompareStencilMaterialProxy::OnBind( C_BaseEntity *pEnt )
  213. {
  214. }
  215. IMaterial *CLumCompareStencilMaterialProxy::GetMaterial()
  216. {
  217. if( s_pLumCompareStencilMaterial == NULL)
  218. {
  219. s_pLumCompareStencilMaterial = materials->FindMaterial( "dev/no_pixel_write", TEXTURE_GROUP_OTHER, true );
  220. }
  221. return s_pLumCompareStencilMaterial;
  222. }
  223. IMaterial *CLumCompareStencilMaterialProxy::GetLumCompareStencilMaterial( IMaterialSystem * materials )
  224. {
  225. if( s_pLumCompareStencilMaterial == NULL)
  226. {
  227. s_pLumCompareStencilMaterial = materials->FindMaterial( "dev/no_pixel_write", TEXTURE_GROUP_OTHER, true );
  228. }
  229. return s_pLumCompareStencilMaterial;
  230. }
  231. EXPOSE_MATERIAL_PROXY( CLumCompareStencilMaterialProxy, no_pixel_write );
  232. //=====================================================================================================================
  233. // Downsample material proxy ============================================================================================
  234. //=====================================================================================================================
  235. class CDownsampleMaterialProxy : public CEntityMaterialProxy
  236. {
  237. public:
  238. CDownsampleMaterialProxy();
  239. virtual ~CDownsampleMaterialProxy() {};
  240. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  241. virtual void OnBind( C_BaseEntity *pEntity );
  242. virtual IMaterial *GetMaterial();
  243. public:
  244. static IMaterial *GetDownsampleMaterial( IMaterialSystem * materials );
  245. static void SetupDownsampleMaterial( float flBloomExponent, float flBloomSaturation );
  246. private:
  247. static IMaterialVar *s_pMaterialParam_bloomexp;
  248. static IMaterialVar *s_pMaterialParam_bloomsaturation;
  249. static float s_bloomexp;
  250. static float s_bloomsaturation;
  251. static IMaterial *s_pDownsampleMaterial;
  252. };
  253. IMaterialVar *CDownsampleMaterialProxy::s_pMaterialParam_bloomexp = NULL;
  254. IMaterialVar *CDownsampleMaterialProxy::s_pMaterialParam_bloomsaturation = NULL;
  255. float CDownsampleMaterialProxy::s_bloomexp = 2.5f;
  256. float CDownsampleMaterialProxy::s_bloomsaturation = 1.0f;
  257. IMaterial *CDownsampleMaterialProxy::s_pDownsampleMaterial = NULL;
  258. CDownsampleMaterialProxy::CDownsampleMaterialProxy()
  259. {
  260. s_pMaterialParam_bloomexp = NULL;
  261. s_pMaterialParam_bloomsaturation = NULL;
  262. s_pDownsampleMaterial = NULL;
  263. }
  264. bool CDownsampleMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  265. {
  266. bool bFoundVar = false;
  267. s_pMaterialParam_bloomexp = pMaterial->FindVar( "$bloomexp", &bFoundVar, false );
  268. s_pMaterialParam_bloomsaturation = pMaterial->FindVar( "$bloomsaturation", &bFoundVar, false );
  269. s_bloomexp = 2.5f;
  270. s_bloomsaturation = 1.0f;
  271. return true;
  272. }
  273. void CDownsampleMaterialProxy::OnBind( C_BaseEntity *pEnt )
  274. {
  275. }
  276. IMaterial *CDownsampleMaterialProxy::GetMaterial()
  277. {
  278. if ( s_pMaterialParam_bloomexp == NULL)
  279. return NULL;
  280. return s_pMaterialParam_bloomexp->GetOwningMaterial();
  281. }
  282. IMaterial *CDownsampleMaterialProxy::GetDownsampleMaterial( IMaterialSystem * materials )
  283. {
  284. if( s_pDownsampleMaterial == NULL)
  285. {
  286. // FIXME: doesn't support dev/downsample (bFloathdr == true) path on PS3 here yet...
  287. s_pDownsampleMaterial = materials->FindMaterial( "dev/downsample_non_hdr", TEXTURE_GROUP_OTHER, true );
  288. }
  289. return s_pDownsampleMaterial;
  290. }
  291. void CDownsampleMaterialProxy::SetupDownsampleMaterial( float flBloomExponent, float flBloomSaturation )
  292. {
  293. s_bloomexp = flBloomExponent;
  294. s_bloomsaturation = flBloomSaturation;
  295. s_pMaterialParam_bloomexp->SetFloatValue( s_bloomexp );
  296. s_pMaterialParam_bloomsaturation->SetFloatValue( s_bloomsaturation );
  297. }
  298. EXPOSE_MATERIAL_PROXY( CDownsampleMaterialProxy, downsample_non_hdr );
  299. //=====================================================================================================================
  300. // XBlur material proxy ============================================================================================
  301. //=====================================================================================================================
  302. class CXBlurMaterialProxy : public CEntityMaterialProxy
  303. {
  304. public:
  305. CXBlurMaterialProxy();
  306. virtual ~CXBlurMaterialProxy() {};
  307. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  308. virtual void OnBind( C_BaseEntity *pEntity );
  309. virtual IMaterial *GetMaterial();
  310. private:
  311. public:
  312. static IMaterial *GetXBlurMaterial( IMaterialSystem * materials );
  313. private:
  314. static IMaterial *s_pXBlurMaterial;
  315. };
  316. IMaterial *CXBlurMaterialProxy::s_pXBlurMaterial = NULL;
  317. CXBlurMaterialProxy::CXBlurMaterialProxy()
  318. {
  319. s_pXBlurMaterial = NULL;
  320. }
  321. bool CXBlurMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  322. {
  323. return true;
  324. }
  325. void CXBlurMaterialProxy::OnBind( C_BaseEntity *pEnt )
  326. {
  327. }
  328. IMaterial *CXBlurMaterialProxy::GetMaterial()
  329. {
  330. if( s_pXBlurMaterial == NULL)
  331. {
  332. s_pXBlurMaterial = materials->FindMaterial( "dev/blurfilterx_nohdr", TEXTURE_GROUP_OTHER, true );
  333. }
  334. return s_pXBlurMaterial;
  335. }
  336. IMaterial *CXBlurMaterialProxy::GetXBlurMaterial( IMaterialSystem * materials )
  337. {
  338. if( s_pXBlurMaterial == NULL)
  339. {
  340. s_pXBlurMaterial = materials->FindMaterial( "dev/blurfilterx_nohdr", TEXTURE_GROUP_OTHER, true );
  341. }
  342. return s_pXBlurMaterial;
  343. }
  344. EXPOSE_MATERIAL_PROXY( CXBlurMaterialProxy, blurfilterx );
  345. //=====================================================================================================================
  346. // YBlur material proxy ============================================================================================
  347. //=====================================================================================================================
  348. class CYBlurMaterialProxy : public CEntityMaterialProxy
  349. {
  350. public:
  351. CYBlurMaterialProxy();
  352. virtual ~CYBlurMaterialProxy() {};
  353. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  354. virtual void OnBind( C_BaseEntity *pEntity );
  355. virtual IMaterial *GetMaterial();
  356. private:
  357. public:
  358. static IMaterial *GetYBlurMaterial( IMaterialSystem * materials );
  359. private:
  360. static IMaterial *s_pYBlurMaterial;
  361. };
  362. IMaterial *CYBlurMaterialProxy::s_pYBlurMaterial = NULL;
  363. CYBlurMaterialProxy::CYBlurMaterialProxy()
  364. {
  365. s_pYBlurMaterial = NULL;
  366. }
  367. bool CYBlurMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  368. {
  369. return true;
  370. }
  371. void CYBlurMaterialProxy::OnBind( C_BaseEntity *pEnt )
  372. {
  373. }
  374. IMaterial *CYBlurMaterialProxy::GetMaterial()
  375. {
  376. if( s_pYBlurMaterial == NULL)
  377. {
  378. s_pYBlurMaterial = materials->FindMaterial( "dev/blurfiltery_nohdr", TEXTURE_GROUP_OTHER, true );
  379. }
  380. return s_pYBlurMaterial;
  381. }
  382. IMaterial *CYBlurMaterialProxy::GetYBlurMaterial( IMaterialSystem * materials )
  383. {
  384. if( s_pYBlurMaterial == NULL)
  385. {
  386. s_pYBlurMaterial = materials->FindMaterial( "dev/blurfiltery_nohdr", TEXTURE_GROUP_OTHER, true );
  387. }
  388. return s_pYBlurMaterial;
  389. }
  390. EXPOSE_MATERIAL_PROXY( CYBlurMaterialProxy, blurfiltery );
  391. static void SetRenderTargetAndViewPort(ITexture *rt)
  392. {
  393. CMatRenderContextPtr pRenderContext( materials );
  394. pRenderContext->SetRenderTarget(rt);
  395. if ( rt )
  396. {
  397. pRenderContext->Viewport(0,0,rt->GetActualWidth(),rt->GetActualHeight());
  398. }
  399. }
  400. enum HistogramEntryState_t
  401. {
  402. HESTATE_INITIAL = 0,
  403. HESTATE_FIRST_QUERY_IN_FLIGHT,
  404. HESTATE_QUERY_IN_FLIGHT,
  405. HESTATE_QUERY_DONE,
  406. };
  407. #define NUM_HISTOGRAM_BUCKETS 31
  408. #define NUM_HISTOGRAM_BUCKETS_NEW 17
  409. #define MAX_QUERIES_PER_FRAME 1
  410. class CHistogramBucket
  411. {
  412. public:
  413. HistogramEntryState_t m_state;
  414. OcclusionQueryObjectHandle_t m_hOcclusionQueryHandle;
  415. int m_nFrameQueued; // when this query was last queued
  416. int m_nPixels; // # of pixels this histogram represents
  417. int m_nPixelsInRange;
  418. float m_flMinLuminance, m_flMaxLuminance; // the luminance range this entry was queried with
  419. float m_flScreenMinX, m_flScreenMinY, m_flScreenMaxX, m_flScreenMaxY; // range is 0..1 in fractions of the screen
  420. bool ContainsValidData( void )
  421. {
  422. return ( m_state == HESTATE_QUERY_DONE ) || ( m_state == HESTATE_QUERY_IN_FLIGHT );
  423. }
  424. void IssueQuery( int nFrameNum );
  425. };
  426. void CHistogramBucket::IssueQuery( int nFrameNum )
  427. {
  428. CMatRenderContextPtr pRenderContext( materials );
  429. if ( !m_hOcclusionQueryHandle )
  430. {
  431. m_hOcclusionQueryHandle = pRenderContext->CreateOcclusionQueryObject();
  432. }
  433. int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
  434. pRenderContext->GetViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
  435. // Find min and max gamma-space text range
  436. float flTestRangeMin = ( m_flMinLuminance == 0.0f ) ? -1e20f : m_flMinLuminance; // Count all pixels < 0.0 as 0.0 (for float HDR buffers)
  437. float flTestRangeMax = ( m_flMaxLuminance == 1.0f ) ? 1e20f : m_flMaxLuminance; // Count all pixels >1.0 as 1.0
  438. // Set stencil bits where the colors match
  439. IMaterial *pLumCompareMaterial;
  440. #if defined(_PS3)
  441. if( mat_PS3_findpostvarsfast.GetInt() )
  442. {
  443. pLumCompareMaterial = CLumCompareMaterialProxy::GetLumCompareMaterial( materials );
  444. CLumCompareMaterialProxy::SetupLumCompareMaterial( flTestRangeMin, flTestRangeMax );
  445. }
  446. else
  447. #endif
  448. {
  449. pLumCompareMaterial = materials->FindMaterial( "dev/lumcompare", TEXTURE_GROUP_OTHER, true );
  450. IMaterialVar *pMinVar = pLumCompareMaterial->FindVar( "$C0_X", NULL );
  451. pMinVar->SetFloatValue( flTestRangeMin );
  452. IMaterialVar *pMaxVar = pLumCompareMaterial->FindVar( "$C0_Y", NULL );
  453. pMaxVar->SetFloatValue( flTestRangeMax );
  454. }
  455. int nScreenMinX = FLerp( nViewportX, ( nViewportX + nViewportWidth - 1 ), 0, 1, m_flScreenMinX );
  456. int nScreenMaxX = FLerp( nViewportX, ( nViewportX + nViewportWidth - 1 ), 0, 1, m_flScreenMaxX );
  457. int nScreenMinY = FLerp( nViewportY, ( nViewportY + nViewportHeight - 1 ), 0, 1, m_flScreenMinY );
  458. int nScreenMaxY = FLerp( nViewportY, ( nViewportY + nViewportHeight - 1 ), 0, 1, m_flScreenMaxY );
  459. float flExposureWidthScale, flExposureHeightScale;
  460. // Shrink region of interest if the flashlight is on
  461. flExposureWidthScale = ( 0.5f * ( 1.0f - mat_exposure_center_region_x.GetFloat() ) );
  462. flExposureHeightScale = ( 0.5f * ( 1.0f - mat_exposure_center_region_y.GetFloat() ) );
  463. int nBorderWidth = ( nScreenMaxX - nScreenMinX + 1 ) * flExposureWidthScale;
  464. int nBorderHeight = ( nScreenMaxY - nScreenMinY + 1 ) * flExposureHeightScale;
  465. // Do luminance compare
  466. m_nPixels = ( 1 + nScreenMaxX - nScreenMinX ) * ( 1 + nScreenMaxY - nScreenMinY );
  467. ShaderStencilState_t state;
  468. if ( mat_tonemapping_occlusion_use_stencil.GetInt() )
  469. {
  470. state.m_nWriteMask = 1;
  471. state.m_bEnable = true;
  472. state.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  473. state.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  474. state.m_FailOp = SHADER_STENCILOP_KEEP;
  475. state.m_ZFailOp = SHADER_STENCILOP_KEEP;
  476. state.m_nReferenceValue = 0x80;
  477. state.m_nWriteMask = 0x80;
  478. pRenderContext->SetStencilState( state );
  479. }
  480. else
  481. {
  482. pRenderContext->BeginOcclusionQueryDrawing( m_hOcclusionQueryHandle );
  483. }
  484. int nWindowWidth = 0;
  485. int nWindowHeight = 0;
  486. pRenderContext->GetWindowSize( nWindowWidth, nWindowHeight );
  487. nScreenMinX += nBorderWidth;
  488. nScreenMinY += nBorderHeight;
  489. nScreenMaxX -= nBorderWidth;
  490. nScreenMaxY -= nBorderHeight;
  491. pRenderContext->DrawScreenSpaceRectangle( pLumCompareMaterial,
  492. nScreenMinX - nViewportX, nScreenMinY - nViewportY,
  493. 1 + nScreenMaxX - nScreenMinX,
  494. 1 + nScreenMaxY - nScreenMinY,
  495. nScreenMinX, nScreenMinY,
  496. nScreenMaxX, nScreenMaxY,
  497. nWindowWidth, nWindowHeight );
  498. if ( mat_tonemapping_occlusion_use_stencil.GetInt() )
  499. {
  500. // Start counting how many pixels had their stencil bit set via an occlusion query
  501. pRenderContext->BeginOcclusionQueryDrawing( m_hOcclusionQueryHandle );
  502. // Issue an occlusion query using stencil as the mask
  503. state.m_bEnable = true;
  504. state.m_nTestMask = 0x80;
  505. state.m_PassOp = SHADER_STENCILOP_KEEP;
  506. state.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  507. state.m_FailOp = SHADER_STENCILOP_KEEP;
  508. state.m_ZFailOp = SHADER_STENCILOP_KEEP;
  509. state.m_nReferenceValue = 0x80;
  510. pRenderContext->SetStencilState( state );
  511. IMaterial *pLumCompareStencilMaterial;
  512. #if defined(_PS3)
  513. if( mat_PS3_findpostvarsfast.GetInt() )
  514. pLumCompareStencilMaterial = CLumCompareStencilMaterialProxy::GetLumCompareStencilMaterial( materials );
  515. else
  516. #endif
  517. pLumCompareStencilMaterial = materials->FindMaterial( "dev/no_pixel_write", TEXTURE_GROUP_OTHER, true);
  518. pRenderContext->DrawScreenSpaceRectangle( pLumCompareStencilMaterial,
  519. nScreenMinX, nScreenMinY,
  520. 1 + nScreenMaxX - nScreenMinX,
  521. 1 + nScreenMaxY - nScreenMinY,
  522. nScreenMinX, nScreenMinY,
  523. nScreenMaxX, nScreenMaxY,
  524. nWindowWidth, nWindowHeight );
  525. ShaderStencilState_t stateDisable;
  526. stateDisable.m_bEnable = false;
  527. pRenderContext->SetStencilState( stateDisable );
  528. }
  529. pRenderContext->EndOcclusionQueryDrawing( m_hOcclusionQueryHandle );
  530. if ( m_state == HESTATE_INITIAL )
  531. m_state = HESTATE_FIRST_QUERY_IN_FLIGHT;
  532. else
  533. m_state = HESTATE_QUERY_IN_FLIGHT;
  534. m_nFrameQueued = nFrameNum;
  535. }
  536. #define HISTOGRAM_BAR_SIZE 200
  537. class CTonemapSystem
  538. {
  539. CHistogramBucket m_histogramBucketArray[NUM_HISTOGRAM_BUCKETS];
  540. int m_nCurrentQueryFrame;
  541. int m_nCurrentAlgorithm;
  542. float m_flTargetTonemapScale;
  543. float m_flCurrentTonemapScale;
  544. int m_nNumMovingAverageValid;
  545. float m_movingAverageTonemapScale[10];
  546. bool m_bOverrideTonemapScaleEnabled;
  547. float m_flOverrideTonemapScale;
  548. public:
  549. void IssueAndReceiveBucketQueries();
  550. void UpdateBucketRanges();
  551. float FindLocationOfPercentBrightPixels( float flPercentBrightPixels, float flPercentTarget );
  552. float ComputeTargetTonemapScalar( bool bGetIdealTargetForDebugMode );
  553. void UpdateMaterialSystemTonemapScalar();
  554. void SetTargetTonemappingScale( float flTonemapScale );
  555. void ResetTonemappingScale( float flTonemapScale );
  556. void SetTonemapScale( IMatRenderContext *pRenderContext, float newvalue, float minvalue, float maxvalue );
  557. float GetTargetTonemappingScale() { return m_flTargetTonemapScale; }
  558. float GetCurrentTonemappingScale() { return m_flCurrentTonemapScale; }
  559. void SetOverrideTonemapScale( bool bEnableOverride, float flTonemapScale );
  560. // Dev functions
  561. void DisplayHistogram();
  562. // Constructor
  563. CTonemapSystem()
  564. {
  565. m_nCurrentQueryFrame = 0;
  566. m_nCurrentAlgorithm = -1;
  567. m_flTargetTonemapScale = 1.0f;
  568. m_flCurrentTonemapScale = 1.0f;
  569. m_nNumMovingAverageValid = 0;
  570. for ( int i = 0; i < ARRAYSIZE( m_movingAverageTonemapScale ) - 1; i++ )
  571. {
  572. m_movingAverageTonemapScale[i] = 1.0f;
  573. }
  574. m_bOverrideTonemapScaleEnabled = false;
  575. m_flOverrideTonemapScale = 1.0f;
  576. UpdateBucketRanges();
  577. }
  578. };
  579. CTonemapSystem * GetCurrentTonemappingSystem()
  580. {
  581. static CTonemapSystem s_HDR_HistogramSystem[ MAX_SPLITSCREEN_PLAYERS ];
  582. int slot = GET_ACTIVE_SPLITSCREEN_SLOT();
  583. return &( s_HDR_HistogramSystem[ slot ] );
  584. }
  585. void CTonemapSystem::IssueAndReceiveBucketQueries()
  586. {
  587. UpdateBucketRanges();
  588. // Find which histogram entries should have something done this frame
  589. int nQueriesIssuedThisFrame = 0;
  590. m_nCurrentQueryFrame++;
  591. int nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS;
  592. if ( mat_tonemap_algorithm.GetInt() == 1 )
  593. nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS_NEW;
  594. for ( int i = 0; i < nNumHistogramBuckets; i++ )
  595. {
  596. switch ( m_histogramBucketArray[i].m_state )
  597. {
  598. case HESTATE_INITIAL:
  599. if ( nQueriesIssuedThisFrame<MAX_QUERIES_PER_FRAME )
  600. {
  601. m_histogramBucketArray[i].IssueQuery(m_nCurrentQueryFrame);
  602. nQueriesIssuedThisFrame++;
  603. }
  604. break;
  605. case HESTATE_FIRST_QUERY_IN_FLIGHT:
  606. case HESTATE_QUERY_IN_FLIGHT:
  607. if ( m_nCurrentQueryFrame > m_histogramBucketArray[i].m_nFrameQueued + 2 )
  608. {
  609. CMatRenderContextPtr pRenderContext( materials );
  610. int np = pRenderContext->OcclusionQuery_GetNumPixelsRendered(
  611. m_histogramBucketArray[i].m_hOcclusionQueryHandle );
  612. if ( np != -1 ) // -1 = Query not finished...wait until next time
  613. {
  614. m_histogramBucketArray[i].m_nPixelsInRange = np;
  615. m_histogramBucketArray[i].m_state = HESTATE_QUERY_DONE;
  616. }
  617. }
  618. break;
  619. }
  620. }
  621. // Now, issue queries for the oldest finished queries we have
  622. while ( nQueriesIssuedThisFrame < MAX_QUERIES_PER_FRAME )
  623. {
  624. int nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS;
  625. if ( mat_tonemap_algorithm.GetInt() == 1 )
  626. nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS_NEW;
  627. int nOldestSoFar = -1;
  628. for ( int i = 0; i < nNumHistogramBuckets; i++ )
  629. {
  630. if ( ( m_histogramBucketArray[i].m_state == HESTATE_QUERY_DONE ) &&
  631. ( ( nOldestSoFar == -1 ) || ( m_histogramBucketArray[i].m_nFrameQueued < m_histogramBucketArray[nOldestSoFar].m_nFrameQueued ) ) )
  632. {
  633. nOldestSoFar = i;
  634. }
  635. }
  636. if ( nOldestSoFar == -1 ) // Nothing to do
  637. break;
  638. m_histogramBucketArray[nOldestSoFar].IssueQuery( m_nCurrentQueryFrame );
  639. nQueriesIssuedThisFrame++;
  640. }
  641. }
  642. float CTonemapSystem::FindLocationOfPercentBrightPixels( float flPercentBrightPixels, float flPercentTargetToSnapToIfInSameBin = -1.0f )
  643. {
  644. if ( mat_tonemap_algorithm.GetInt() == 1 ) // New algorithm
  645. {
  646. int nTotalValidPixels = 0;
  647. for ( int i = 0; i < ( NUM_HISTOGRAM_BUCKETS_NEW - 1 ); i++ )
  648. {
  649. if ( m_histogramBucketArray[i].ContainsValidData() )
  650. {
  651. nTotalValidPixels += m_histogramBucketArray[i].m_nPixelsInRange;
  652. }
  653. }
  654. if ( nTotalValidPixels == 0 )
  655. {
  656. return -1.0f;
  657. }
  658. // Find where percent range border is
  659. float flTotalPercentRangeTested = 0.0f;
  660. float flTotalPercentPixelsTested = 0.0f;
  661. for ( int i = ( NUM_HISTOGRAM_BUCKETS_NEW - 2 ); i >= 0; i-- ) // Start at the bright end
  662. {
  663. if ( !m_histogramBucketArray[i].ContainsValidData() )
  664. return -1.0f;
  665. float flPixelPercentNeeded = ( flPercentBrightPixels / 100.0f ) - flTotalPercentPixelsTested;
  666. float flThisBinPercentOfTotalPixels = float( m_histogramBucketArray[i].m_nPixelsInRange ) / float( nTotalValidPixels );
  667. float flThisBinLuminanceRange = m_histogramBucketArray[i].m_flMaxLuminance - m_histogramBucketArray[i].m_flMinLuminance;
  668. if ( flThisBinPercentOfTotalPixels >= flPixelPercentNeeded ) // We found the bin needed
  669. {
  670. if ( flPercentTargetToSnapToIfInSameBin >= 0.0f )
  671. {
  672. if ( ( m_histogramBucketArray[i].m_flMinLuminance <= ( flPercentTargetToSnapToIfInSameBin / 100.0f ) ) && ( m_histogramBucketArray[i].m_flMaxLuminance >= ( flPercentTargetToSnapToIfInSameBin / 100.0f ) ) )
  673. {
  674. // Sticky bin...We're in the same bin as the target so keep the tonemap scale where it is
  675. return ( flPercentTargetToSnapToIfInSameBin / 100.0f );
  676. }
  677. }
  678. float flPercentOfThesePixelsNeeded = flPixelPercentNeeded / flThisBinPercentOfTotalPixels;
  679. float flPercentLocationOfBorder = 1.0f - ( flTotalPercentRangeTested + ( flThisBinLuminanceRange * flPercentOfThesePixelsNeeded ) );
  680. flPercentLocationOfBorder = MAX( m_histogramBucketArray[i].m_flMinLuminance, MIN( m_histogramBucketArray[i].m_flMaxLuminance, flPercentLocationOfBorder ) ); // Clamp to this bin just in case
  681. return flPercentLocationOfBorder;
  682. }
  683. flTotalPercentPixelsTested += flThisBinPercentOfTotalPixels;
  684. flTotalPercentRangeTested += flThisBinLuminanceRange;
  685. }
  686. return -1.0f;
  687. }
  688. else
  689. {
  690. // Don't know what to do for other algorithms yet
  691. return -1.0f;
  692. }
  693. }
  694. float CTonemapSystem::ComputeTargetTonemapScalar( bool bGetIdealTargetForDebugMode = false )
  695. {
  696. if ( mat_tonemap_algorithm.GetInt() == 1 ) // New algorithm
  697. {
  698. float flTonemapPercentTarget = mat_force_tonemap_percent_target.GetFloat() >= 0.0f ? mat_force_tonemap_percent_target.GetFloat() : g_flTonemapPercentTarget;
  699. float flTonemapPercentBrightPixels = mat_force_tonemap_percent_bright_pixels.GetFloat() >= 0.0f ? mat_force_tonemap_percent_bright_pixels.GetFloat() : g_flTonemapPercentBrightPixels;
  700. float flTonemapMinAvgLum = mat_force_tonemap_min_avglum.GetFloat() >= 0.0f ? mat_force_tonemap_min_avglum.GetFloat() : g_flTonemapMinAvgLum;
  701. float flPercentLocationOfTarget;
  702. if ( bGetIdealTargetForDebugMode == true)
  703. flPercentLocationOfTarget = FindLocationOfPercentBrightPixels( flTonemapPercentBrightPixels ); // Don't pass in the second arg so the scalar doesn't snap to a bin
  704. else
  705. flPercentLocationOfTarget = FindLocationOfPercentBrightPixels( flTonemapPercentBrightPixels, flTonemapPercentTarget );
  706. if ( flPercentLocationOfTarget < 0.0f ) // This is the return error code
  707. {
  708. flPercentLocationOfTarget = flTonemapPercentTarget / 100.0f; // Pretend we're at the target
  709. }
  710. // Make sure this is > 0.0f
  711. flPercentLocationOfTarget = MAX( 0.0001f, flPercentLocationOfTarget );
  712. // Compute target scalar
  713. float flTargetScalar = ( flTonemapPercentTarget / 100.0f ) / flPercentLocationOfTarget;
  714. // Compute secondary target scalar
  715. float flAverageLuminanceLocation = FindLocationOfPercentBrightPixels( 50.0f );
  716. if ( flAverageLuminanceLocation > 0.0f )
  717. {
  718. float flTargetScalar2 = ( flTonemapMinAvgLum / 100.0f ) / flAverageLuminanceLocation;
  719. // Only override it if it's trying to brighten the image more than the primary algorithm
  720. if ( flTargetScalar2 > flTargetScalar )
  721. {
  722. flTargetScalar = flTargetScalar2;
  723. }
  724. }
  725. // Apply this against last frames scalar
  726. CMatRenderContextPtr pRenderContext( materials );
  727. float flLastScale = m_flCurrentTonemapScale;
  728. flTargetScalar *= flLastScale;
  729. flTargetScalar = MAX( 0.001f, flTargetScalar );
  730. return flTargetScalar;
  731. }
  732. else // Original tonemapping algorithm
  733. {
  734. float flScaleValue = 1.0f;
  735. if ( m_histogramBucketArray[NUM_HISTOGRAM_BUCKETS-1].ContainsValidData() )
  736. {
  737. flScaleValue = m_histogramBucketArray[NUM_HISTOGRAM_BUCKETS-1].m_nPixels * ( 1.0f / m_histogramBucketArray[NUM_HISTOGRAM_BUCKETS-1].m_nPixelsInRange );
  738. }
  739. if ( !IsFinite( flScaleValue ) )
  740. {
  741. flScaleValue = 1.0f;
  742. }
  743. float flTotal = 0.0f;
  744. int nTotalPixels = 0;
  745. for ( int i=0; i<NUM_HISTOGRAM_BUCKETS-1; i++ )
  746. {
  747. if ( m_histogramBucketArray[i].ContainsValidData() )
  748. {
  749. flTotal += flScaleValue * m_histogramBucketArray[i].m_nPixelsInRange * AVG( m_histogramBucketArray[i].m_flMinLuminance, m_histogramBucketArray[i].m_flMaxLuminance );
  750. nTotalPixels += m_histogramBucketArray[i].m_nPixels;
  751. }
  752. }
  753. float flAverageLuminance = 0.5f;
  754. if ( nTotalPixels > 0 )
  755. flAverageLuminance = flTotal * ( 1.0f / nTotalPixels );
  756. else
  757. flAverageLuminance = 0.5f;
  758. // Make sure this is > 0.0f
  759. flAverageLuminance = MAX( 0.0001f, flAverageLuminance );
  760. // Compute target scalar
  761. float flTargetScalar = 0.005f / flAverageLuminance;
  762. return flTargetScalar;
  763. }
  764. }
  765. static float GetCurrentBloomScale( void )
  766. {
  767. // Use the appropriate bloom scale settings. Mapmakers's overrides the convar settings.
  768. float flCurrentBloomScale = 1.0f;
  769. if ( g_bUseCustomBloomScale )
  770. {
  771. flCurrentBloomScale = g_flCustomBloomScale;
  772. }
  773. else
  774. {
  775. flCurrentBloomScale = mat_bloomscale.GetFloat();
  776. }
  777. return flCurrentBloomScale;
  778. }
  779. static void GetExposureRange( float *pflAutoExposureMin, float *pflAutoExposureMax )
  780. {
  781. // Get min
  782. if ( ( g_bUseCustomAutoExposureMin ) && ( g_flCustomAutoExposureMin > 0.0f ) )
  783. {
  784. *pflAutoExposureMin = g_flCustomAutoExposureMin;
  785. }
  786. else
  787. {
  788. *pflAutoExposureMin = mat_autoexposure_min.GetFloat();
  789. }
  790. // Get max
  791. if ( ( g_bUseCustomAutoExposureMax ) && ( g_flCustomAutoExposureMax > 0.0f ) )
  792. {
  793. *pflAutoExposureMax = g_flCustomAutoExposureMax;
  794. }
  795. else
  796. {
  797. *pflAutoExposureMax = mat_autoexposure_max.GetFloat();
  798. }
  799. *pflAutoExposureMax *= mat_autoexposure_max_multiplier.GetFloat();
  800. // Override
  801. if ( mat_hdr_uncapexposure.GetInt() )
  802. {
  803. *pflAutoExposureMax = 100.0f;
  804. *pflAutoExposureMin = 0.0f;
  805. }
  806. // Make sure min <= max
  807. if ( *pflAutoExposureMin > *pflAutoExposureMax )
  808. {
  809. *pflAutoExposureMax = *pflAutoExposureMin;
  810. }
  811. }
  812. void CTonemapSystem::UpdateBucketRanges()
  813. {
  814. // Only update if our mode changed
  815. if ( m_nCurrentAlgorithm == mat_tonemap_algorithm.GetInt() )
  816. return;
  817. m_nCurrentAlgorithm = mat_tonemap_algorithm.GetInt();
  818. //==================================================================//
  819. // Force fallback to original tone mapping algorithm for these mods //
  820. //==================================================================//
  821. static bool s_bFirstTime = true;
  822. if ( engine == NULL )
  823. {
  824. // Force this code to get hit again so we can change algorithm based on the client
  825. m_nCurrentAlgorithm = -1;
  826. }
  827. else if ( s_bFirstTime == true )
  828. {
  829. s_bFirstTime = false;
  830. // This seems like a bad idea but it's fine for now
  831. const char *sModsForOriginalAlgorithm[] = { "dod", "cstrike", "lostcoast" };
  832. for ( int i=0; i<3; i++ )
  833. {
  834. if ( strlen( engine->GetGameDirectory() ) >= strlen( sModsForOriginalAlgorithm[i] ) )
  835. {
  836. if ( stricmp( &( engine->GetGameDirectory()[strlen( engine->GetGameDirectory() ) - strlen( sModsForOriginalAlgorithm[i] )] ), sModsForOriginalAlgorithm[i] ) == 0 )
  837. {
  838. mat_tonemap_algorithm.SetValue( 0 ); // Original algorithm
  839. m_nCurrentAlgorithm = mat_tonemap_algorithm.GetInt();
  840. break;
  841. }
  842. }
  843. }
  844. }
  845. // Get num buckets
  846. int nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS;
  847. if ( mat_tonemap_algorithm.GetInt() == 1 )
  848. nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS_NEW;
  849. m_nCurrentQueryFrame = 0;
  850. for ( int nBucket = 0; nBucket < nNumHistogramBuckets; nBucket++ )
  851. {
  852. CHistogramBucket *pBucket = &( m_histogramBucketArray[ nBucket ] );
  853. pBucket->m_state = HESTATE_INITIAL;
  854. pBucket->m_flScreenMinX = 0.0f;
  855. pBucket->m_flScreenMaxX = 1.0f;
  856. pBucket->m_flScreenMinY = 0.0f;
  857. pBucket->m_flScreenMaxY = 1.0f;
  858. if ( nBucket != ( nNumHistogramBuckets - 1 ) ) // Last bucket is special
  859. {
  860. if ( mat_tonemap_algorithm.GetInt() == 0 ) // Original algorithm
  861. {
  862. // Use a logarithmic ramp for high range in the low range
  863. pBucket->m_flMinLuminance = -0.01f + exp( FLerp( log( 0.01f ), log( 0.01f + 1.0f ), 0.0f, nNumHistogramBuckets - 1.0f, nBucket ) );
  864. pBucket->m_flMaxLuminance = -0.01f + exp( FLerp( log( 0.01f ), log( 0.01f + 1.0f ), 0.0f, nNumHistogramBuckets - 1.0f, nBucket + 1.0f ) );
  865. }
  866. else
  867. {
  868. // Use even distribution
  869. pBucket->m_flMinLuminance = float( nBucket ) / float( nNumHistogramBuckets - 1 );
  870. pBucket->m_flMaxLuminance = float( nBucket + 1 ) / float( nNumHistogramBuckets - 1 );
  871. // Use a distribution with slightly more bins in the low range
  872. pBucket->m_flMinLuminance = pBucket->m_flMinLuminance > 0.0f ? powf( pBucket->m_flMinLuminance, 2.5f ) : pBucket->m_flMinLuminance;
  873. pBucket->m_flMaxLuminance = pBucket->m_flMaxLuminance > 0.0f ? powf( pBucket->m_flMaxLuminance, 2.5f ) : pBucket->m_flMaxLuminance;
  874. }
  875. }
  876. else
  877. {
  878. // The last bucket is used as a test to determine the return range for occlusion
  879. // queries to use as a scale factor. some boards (nvidia) have their occlusion
  880. // query return values larger when using AA.
  881. pBucket->m_flMinLuminance = 0.0f;
  882. pBucket->m_flMaxLuminance = 100000.0f;
  883. }
  884. //Warning( "Bucket %d: min/max %f / %f ", nBucket, pBucket->m_flMinLuminance, pBucket->m_flMaxLuminance );
  885. }
  886. }
  887. void CTonemapSystem::SetOverrideTonemapScale( bool bEnableOverride, float flTonemapScale )
  888. {
  889. m_bOverrideTonemapScaleEnabled = bEnableOverride;
  890. m_flOverrideTonemapScale = flTonemapScale;
  891. }
  892. void CTonemapSystem::DisplayHistogram()
  893. {
  894. if ( !mat_show_histogram.GetInt() || !mat_dynamic_tonemapping.GetInt() || ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) )
  895. return;
  896. // Get render context
  897. CMatRenderContextPtr pRenderContext( materials );
  898. pRenderContext->PushRenderTargetAndViewport();
  899. // Prep variables for drawing histogram
  900. int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
  901. pRenderContext->GetViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
  902. // Get num bins
  903. int nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS-1;
  904. if ( mat_tonemap_algorithm.GetInt() == 1 )
  905. nNumHistogramBuckets = NUM_HISTOGRAM_BUCKETS_NEW-1;
  906. // Count total pixels in current bins
  907. int nMaxValidPixels = 0;
  908. int nTotalValidPixels = 0;
  909. int nTotalGraphPixelsWide = 0;
  910. for ( int nBucket = 0; nBucket < nNumHistogramBuckets; nBucket++ )
  911. {
  912. CHistogramBucket *pBucket = &( m_histogramBucketArray[ nBucket ] );
  913. if ( pBucket->ContainsValidData() )
  914. {
  915. nTotalValidPixels += pBucket->m_nPixelsInRange;
  916. if ( pBucket->m_nPixelsInRange > nMaxValidPixels )
  917. {
  918. nMaxValidPixels = pBucket->m_nPixelsInRange;
  919. }
  920. }
  921. int nWidth = MAX( 1, 500 * ( pBucket->m_flMaxLuminance - pBucket->m_flMinLuminance ) );
  922. nTotalGraphPixelsWide += nWidth + 2;
  923. }
  924. // Clear background to gray for screenshots
  925. //int nBoxWidth = ( nTotalGraphPixelsWide + 20 );
  926. //pRenderContext->ClearColor3ub( 150, 150, 150 );
  927. //pRenderContext->Viewport( nViewportWidth - nBoxWidth, 0, nBoxWidth, 245 );
  928. //pRenderContext->ClearBuffers( true, true );
  929. // Output some text data
  930. if ( !IsGameConsole() && ( mat_show_histogram.GetInt() == 1 ) )
  931. {
  932. float flTonemapMinAvgLum = mat_force_tonemap_min_avglum.GetFloat() >= 0.0f ? mat_force_tonemap_min_avglum.GetFloat() : g_flTonemapMinAvgLum;
  933. engine->Con_NPrintf( 23 + ( nViewportY / 10 ), "(Histogram luminance is in linear space)" );
  934. engine->Con_NPrintf( 27 + ( nViewportY / 10 ), "AvgLum @ %4.2f%% flTonemapMinAvgLum = %4.2f%% Using %d pixels Override(%s): %4.2f",
  935. MAX( 0.0f, FindLocationOfPercentBrightPixels( 50.0f ) ) * 100.0f, flTonemapMinAvgLum, nTotalValidPixels, m_bOverrideTonemapScaleEnabled ? "On" : "Off", m_flOverrideTonemapScale );
  936. engine->Con_NPrintf( 29 + ( nViewportY / 10 ), "BloomScale = %4.2f flTonemapRate = %4.2f mat_accelerate_adjust_exposure_down = %4.2f",
  937. GetCurrentBloomScale(), g_flTonemapRate, mat_accelerate_adjust_exposure_down.GetFloat() );
  938. }
  939. int xpStart = nViewportX + nViewportWidth - nTotalGraphPixelsWide - 10;
  940. if ( IsGameConsole() )
  941. {
  942. xpStart -= 50;
  943. }
  944. int yOffset = 4 + nViewportY;
  945. if ( mat_show_histogram.GetInt() == 1 )
  946. {
  947. int xp = xpStart;
  948. for ( int nBucket = 0; nBucket < nNumHistogramBuckets; nBucket++ )
  949. {
  950. int np = 0;
  951. CHistogramBucket &e = m_histogramBucketArray[ nBucket ];
  952. if ( e.ContainsValidData() )
  953. np += e.m_nPixelsInRange;
  954. int width = MAX( 1, 500 * ( e.m_flMaxLuminance - e.m_flMinLuminance ) );
  955. //Warning( "Bucket %d: min/max %f / %f. m_nPixelsInRange=%d m_nPixels=%d\n", nBucket, e.m_flMinLuminance, e.m_flMaxLuminance, e.m_nPixelsInRange, e.m_nPixels );
  956. if ( np )
  957. {
  958. int height = MAX( 1, MIN( HISTOGRAM_BAR_SIZE, ( (float)np / (float)nMaxValidPixels ) * HISTOGRAM_BAR_SIZE ) );
  959. pRenderContext->ClearColor3ub( 255, 0, 0 );
  960. pRenderContext->Viewport( xp, yOffset + HISTOGRAM_BAR_SIZE - height, width, height );
  961. pRenderContext->ClearBuffers( true, true );
  962. }
  963. else
  964. {
  965. int height = 1;
  966. pRenderContext->ClearColor3ub( 0, 0, 0 );
  967. pRenderContext->Viewport( xp, yOffset + HISTOGRAM_BAR_SIZE - height, width, height );
  968. pRenderContext->ClearBuffers( true, true );
  969. }
  970. xp += width + 2;
  971. }
  972. if ( mat_tonemap_algorithm.GetInt() == 1 ) // New algorithm only
  973. {
  974. float flTonemapPercentTarget = mat_force_tonemap_percent_target.GetFloat() >= 0.0f ? mat_force_tonemap_percent_target.GetFloat() : g_flTonemapPercentTarget;
  975. float flYellowTargetPixelStart = ( xpStart + ( float( nTotalGraphPixelsWide ) * flTonemapPercentTarget / 100.0f ) );
  976. float flTonemapMinAvgLum = mat_force_tonemap_min_avglum.GetFloat() >= 0.0f ? mat_force_tonemap_min_avglum.GetFloat() : g_flTonemapMinAvgLum;
  977. float flYellowAveragePixelStart = ( xpStart + ( float( nTotalGraphPixelsWide ) * flTonemapMinAvgLum / 100.0f ) );
  978. float flTonemapPercentBrightPixels = mat_force_tonemap_percent_bright_pixels.GetFloat() >= 0.0f ? mat_force_tonemap_percent_bright_pixels.GetFloat() : g_flTonemapPercentBrightPixels;
  979. float flTargetPixelStart = ( xpStart + ( float( nTotalGraphPixelsWide ) * FindLocationOfPercentBrightPixels( flTonemapPercentBrightPixels, flTonemapPercentTarget ) ) );
  980. float flAveragePixelStart = ( xpStart + ( float( nTotalGraphPixelsWide ) * FindLocationOfPercentBrightPixels( 50.0f ) ) );
  981. // Draw target yellow border bar
  982. int nHeight = HISTOGRAM_BAR_SIZE * 3 / 4;
  983. int nHeightOffset = -( HISTOGRAM_BAR_SIZE - nHeight ) / 2;
  984. // Green is current percent target location
  985. pRenderContext->Viewport( flYellowTargetPixelStart-1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight - 2, 8, nHeight + 4 );
  986. pRenderContext->ClearColor3ub( 0, 127, 0 );
  987. pRenderContext->ClearBuffers( true, true );
  988. pRenderContext->Viewport( flYellowTargetPixelStart+1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight, 4, nHeight );
  989. pRenderContext->ClearColor3ub( 0, 0, 0 );
  990. pRenderContext->ClearBuffers( true, true );
  991. pRenderContext->Viewport( flTargetPixelStart+1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight, 4, nHeight );
  992. pRenderContext->ClearColor3ub( 0, 255, 0 );
  993. pRenderContext->ClearBuffers( true, true );
  994. // Blue is average luminance location
  995. pRenderContext->Viewport( flYellowAveragePixelStart-1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight - 2, 8, nHeight + 4 );
  996. pRenderContext->ClearColor3ub( 0, 114, 188 );
  997. pRenderContext->ClearBuffers( true, true );
  998. pRenderContext->Viewport( flYellowAveragePixelStart+1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight, 4, nHeight );
  999. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1000. pRenderContext->ClearBuffers( true, true );
  1001. pRenderContext->Viewport( flAveragePixelStart+1, yOffset + nHeightOffset + HISTOGRAM_BAR_SIZE - nHeight, 4, nHeight );
  1002. pRenderContext->ClearColor3ub( 0, 191, 243 );
  1003. pRenderContext->ClearBuffers( true, true );
  1004. }
  1005. }
  1006. // Show actual tonemap value
  1007. if ( 1 )
  1008. {
  1009. float flAutoExposureMin;
  1010. float flAutoExposureMax;
  1011. GetExposureRange( &flAutoExposureMin, &flAutoExposureMax );
  1012. float flBarWidth = nTotalGraphPixelsWide;
  1013. float flBarStart = xpStart;
  1014. float flHistogramBarSize = HISTOGRAM_BAR_SIZE;
  1015. if ( mat_show_histogram.GetInt() == 2 ) // No histogram
  1016. {
  1017. flHistogramBarSize = 0.0f;
  1018. }
  1019. pRenderContext->Viewport( flBarStart, yOffset + flHistogramBarSize - 4 + 20, flBarWidth, 4 );
  1020. pRenderContext->ClearColor3ub( 200, 200, 200 );
  1021. pRenderContext->ClearBuffers( true, true );
  1022. pRenderContext->Viewport( flBarStart, yOffset + flHistogramBarSize - 4 + 20 + 1, flBarWidth, 2 );
  1023. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1024. pRenderContext->ClearBuffers( true, true );
  1025. pRenderContext->Viewport( flBarStart + ( flBarWidth * ( ( m_flCurrentTonemapScale - flAutoExposureMin ) / ( flAutoExposureMax - flAutoExposureMin ) ) ) - 1,
  1026. yOffset + flHistogramBarSize - 4 + 20 - 6 - 1, 4 + 2, 16 + 2 );
  1027. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1028. pRenderContext->ClearBuffers( true, true );
  1029. pRenderContext->Viewport( flBarStart + ( flBarWidth * ( ( m_flCurrentTonemapScale - flAutoExposureMin ) / ( flAutoExposureMax - flAutoExposureMin ) ) ),
  1030. yOffset + flHistogramBarSize - 4 + 20 - 6, 4, 16 );
  1031. pRenderContext->ClearColor3ub( 255, 255, 0 );
  1032. pRenderContext->ClearBuffers( true, true );
  1033. if ( !IsGameConsole() )
  1034. {
  1035. int nHeight = 21;
  1036. if ( mat_show_histogram.GetInt() == 2 ) // No histogram
  1037. {
  1038. nHeight = 1;
  1039. }
  1040. engine->Con_NPrintf( nHeight + ( nViewportY / 10 ), "%.2f %.2f %.2f",
  1041. flAutoExposureMin, ( flAutoExposureMax + flAutoExposureMin ) / 2.0f, flAutoExposureMax );
  1042. }
  1043. }
  1044. // Last bar doesn't clear properly so draw an extra pixel
  1045. pRenderContext->Viewport( 0, 0, 1, 1 );
  1046. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1047. pRenderContext->ClearBuffers( true, true );
  1048. pRenderContext->PopRenderTargetAndViewport();
  1049. }
  1050. // Global postprocessing disable switch
  1051. static bool s_bOverridePostProcessingDisable = false;
  1052. void UpdateMaterialSystemTonemapScalar()
  1053. {
  1054. GetCurrentTonemappingSystem()->UpdateMaterialSystemTonemapScalar();
  1055. }
  1056. void CTonemapSystem::UpdateMaterialSystemTonemapScalar()
  1057. {
  1058. if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
  1059. {
  1060. // Deal with forced tone map scalar
  1061. float flForcedTonemapScale = mat_force_tonemap_scale.GetFloat();
  1062. if ( mat_fullbright.GetInt() == 1 )
  1063. {
  1064. flForcedTonemapScale = 1.0f;
  1065. }
  1066. if ( flForcedTonemapScale > 0.0f )
  1067. {
  1068. ResetTonemappingScale( flForcedTonemapScale );
  1069. // Send this value to the material system
  1070. CMatRenderContextPtr pRenderContext( materials );
  1071. pRenderContext->SetToneMappingScaleLinear( Vector( m_flCurrentTonemapScale, m_flCurrentTonemapScale, m_flCurrentTonemapScale ) );
  1072. return;
  1073. }
  1074. // Override tone map scalar
  1075. if ( m_bOverrideTonemapScaleEnabled )
  1076. {
  1077. float flAutoExposureMin;
  1078. float flAutoExposureMax;
  1079. GetExposureRange( &flAutoExposureMin, &flAutoExposureMax );
  1080. float fScale = clamp( m_flOverrideTonemapScale, flAutoExposureMin, flAutoExposureMax );
  1081. ResetTonemappingScale( fScale );
  1082. // Send this value to the material system
  1083. CMatRenderContextPtr pRenderContext( materials );
  1084. pRenderContext->SetToneMappingScaleLinear( Vector( m_flCurrentTonemapScale, m_flCurrentTonemapScale, m_flCurrentTonemapScale ) );
  1085. return;
  1086. }
  1087. // Send this value to the material system
  1088. CMatRenderContextPtr pRenderContext( materials );
  1089. pRenderContext->SetToneMappingScaleLinear( Vector( m_flCurrentTonemapScale, m_flCurrentTonemapScale, m_flCurrentTonemapScale ) );
  1090. }
  1091. else
  1092. {
  1093. // Send 1.0 to the material system since HDR is disabled
  1094. CMatRenderContextPtr pRenderContext( materials );
  1095. pRenderContext->SetToneMappingScaleLinear( Vector( 1.0f, 1.0f, 1.0f ) );
  1096. }
  1097. }
  1098. void CTonemapSystem::ResetTonemappingScale( float flTonemapScale )
  1099. {
  1100. if ( flTonemapScale <= 0.0f )
  1101. {
  1102. // L4D Hack to reset the tonemapping scale to the average of min and max since we have such dark lighting
  1103. // compared to our other games. 1.0 is no longer a good value when changing spectator targets.
  1104. float flAutoExposureMin = 0.0f;
  1105. float flAutoExposureMax = 0.0f;
  1106. GetExposureRange( &flAutoExposureMin, &flAutoExposureMax );
  1107. flTonemapScale = ( flAutoExposureMin + flAutoExposureMax ) * 0.5f;
  1108. flTonemapScale = clamp( flTonemapScale, 1.0f, 10.0f ); // Restrict this to the 1-10 range
  1109. }
  1110. // Force current and target tonemap scalar
  1111. m_flCurrentTonemapScale = flTonemapScale;
  1112. m_flTargetTonemapScale = flTonemapScale;
  1113. // Clear averaging history
  1114. m_nNumMovingAverageValid = 0;
  1115. }
  1116. void CTonemapSystem::SetTargetTonemappingScale( float flTonemapScale )
  1117. {
  1118. Assert( IsFinite( flTonemapScale ) );
  1119. if ( IsFinite( flTonemapScale ) )
  1120. {
  1121. m_flTargetTonemapScale = flTonemapScale;
  1122. }
  1123. }
  1124. // Local contrast setting
  1125. PostProcessParameters_t s_LocalPostProcessParameters[ MAX_SPLITSCREEN_PLAYERS ];
  1126. // view fade param settings
  1127. static Vector4D s_viewFadeColor[ MAX_SPLITSCREEN_PLAYERS ];
  1128. static bool s_bViewFadeModulate[ MAX_SPLITSCREEN_PLAYERS ];
  1129. class PPInit
  1130. {
  1131. public:
  1132. PPInit()
  1133. {
  1134. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  1135. {
  1136. s_viewFadeColor[ i ].Init( 0.0f, 0.0f, 0.0f, 0.0f );
  1137. s_bViewFadeModulate[ i ] = false;
  1138. }
  1139. }
  1140. };
  1141. static PPInit g_PPInit;
  1142. void ResetToneMapping( float flTonemappingScale )
  1143. {
  1144. GetCurrentTonemappingSystem()->ResetTonemappingScale( flTonemappingScale );
  1145. // Send this value to the material system
  1146. CMatRenderContextPtr pRenderContext( materials );
  1147. pRenderContext->SetToneMappingScaleLinear( Vector( flTonemappingScale, flTonemappingScale, flTonemappingScale ) );
  1148. }
  1149. void CTonemapSystem::SetTonemapScale( IMatRenderContext *pRenderContext, float flTargetTonemapScalar, float flMinValue, float flMaxValue )
  1150. {
  1151. Assert( IsFinite( flTargetTonemapScalar ) );
  1152. if ( !IsFinite( flTargetTonemapScalar ) )
  1153. return;
  1154. //=========================================================================//
  1155. // Save off new target tonemap scalar so we can compute a weighted average //
  1156. //=========================================================================//
  1157. if ( m_nNumMovingAverageValid < ARRAYSIZE( m_movingAverageTonemapScale ))
  1158. {
  1159. m_movingAverageTonemapScale[ m_nNumMovingAverageValid++ ] = flTargetTonemapScalar;
  1160. }
  1161. else
  1162. {
  1163. // Scroll, losing oldest
  1164. for ( int i = 0; i < ARRAYSIZE( m_movingAverageTonemapScale ) - 1; i++ )
  1165. m_movingAverageTonemapScale[ i ] = m_movingAverageTonemapScale[ i + 1 ];
  1166. m_movingAverageTonemapScale[ ARRAYSIZE( m_movingAverageTonemapScale ) - 1 ] = flTargetTonemapScalar;
  1167. }
  1168. //==================================================================//
  1169. // Compute a weighted average of the last 10 target tonemap scalars //
  1170. //==================================================================//
  1171. if ( m_nNumMovingAverageValid == ARRAYSIZE( m_movingAverageTonemapScale ) ) // If we have a full buffer
  1172. {
  1173. float flWeightedAverage = 0.0f;
  1174. float flSumWeights = 0.0f;
  1175. int iMidPoint = ARRAYSIZE( m_movingAverageTonemapScale ) / 2;
  1176. for ( int i = 0; i < ARRAYSIZE( m_movingAverageTonemapScale ); i++ )
  1177. {
  1178. float flWeight = abs( i - iMidPoint ) * ( 1.0f / ( ARRAYSIZE( m_movingAverageTonemapScale ) / 2 ) );
  1179. flSumWeights += flWeight;
  1180. flWeightedAverage += flWeight * m_movingAverageTonemapScale[i];
  1181. }
  1182. flWeightedAverage *= ( 1.0f / flSumWeights );
  1183. flWeightedAverage = clamp( flWeightedAverage, flMinValue, flMaxValue );
  1184. SetTargetTonemappingScale( flWeightedAverage );
  1185. }
  1186. else
  1187. {
  1188. SetTargetTonemappingScale( flTargetTonemapScalar );
  1189. }
  1190. //=======================================//
  1191. // Smoothly lerp to the target over time //
  1192. //=======================================//
  1193. float flElapsedTime = MAX( gpGlobals->frametime, 0.0f ); // Clamp to positive
  1194. float flRate = g_flTonemapRate;
  1195. if ( mat_tonemap_algorithm.GetInt() == 1 )
  1196. {
  1197. flRate *= 2.0f; // Default 2x for the new tone mapping algorithm so it feels the same as the original
  1198. }
  1199. if ( flRate == 0.0f ) // Zero indicates instantaneous tonemap scaling
  1200. {
  1201. m_flCurrentTonemapScale = m_flTargetTonemapScale;
  1202. }
  1203. else
  1204. {
  1205. if ( m_flTargetTonemapScale < m_flCurrentTonemapScale )
  1206. {
  1207. float acc_exposure_adjust = mat_accelerate_adjust_exposure_down.GetFloat();
  1208. // Adjust at up to 4x rate when over-exposed.
  1209. flRate = MIN( ( acc_exposure_adjust * flRate ), FLerp( flRate, ( acc_exposure_adjust * flRate ), 0.0f, 1.5f, ( m_flCurrentTonemapScale - m_flTargetTonemapScale ) ) );
  1210. }
  1211. float flRateTimesTime = flRate * flElapsedTime;
  1212. if ( mat_tonemap_algorithm.GetInt() == 1 )
  1213. {
  1214. // For the new tone mapping algorithm, limit the rate based on the number of bins to
  1215. // help reduce the tone map scalar "riding the wave" of the histogram re-building
  1216. //Warning( "flRateTimesTime = %.4f", flRateTimesTime );
  1217. flRateTimesTime = MIN( flRateTimesTime, ( 1.0f / ( float )( NUM_HISTOGRAM_BUCKETS_NEW - 1 ) ) * 0.25f );
  1218. //Warning( " --> %.4f\n", flRateTimesTime );
  1219. }
  1220. float flAlpha = clamp( flRateTimesTime, 0.0f, 1.0f );
  1221. m_flCurrentTonemapScale = ( m_flTargetTonemapScale * flAlpha ) + ( m_flCurrentTonemapScale * ( 1.0f - flAlpha ) );
  1222. //m_flCurrentTonemapScale = FLerp( m_flCurrentTonemapScale, m_flTargetTonemapScale, flAlpha );
  1223. if ( !IsFinite( m_flCurrentTonemapScale ) )
  1224. {
  1225. Assert( 0 );
  1226. m_flCurrentTonemapScale = m_flTargetTonemapScale;
  1227. }
  1228. }
  1229. //==========================================//
  1230. // Step on values if we're forcing a scalar //
  1231. //==========================================//
  1232. float flForcedTonemapScale = mat_force_tonemap_scale.GetFloat();
  1233. if ( flForcedTonemapScale > 0.0f )
  1234. {
  1235. ResetTonemappingScale( flForcedTonemapScale );
  1236. }
  1237. }
  1238. //=====================================================================================================================
  1239. // Public functions for messing with tone mapping
  1240. //=====================================================================================================================
  1241. float GetCurrentTonemapScale()
  1242. {
  1243. return GetCurrentTonemappingSystem()->GetCurrentTonemappingScale();
  1244. }
  1245. void SetOverrideTonemapScale( bool bEnableOverride, float flTonemapScale )
  1246. {
  1247. GetCurrentTonemappingSystem()->SetOverrideTonemapScale( bEnableOverride, flTonemapScale );
  1248. }
  1249. void SetOverridePostProcessingDisable( bool bForceOff )
  1250. {
  1251. s_bOverridePostProcessingDisable = bForceOff;
  1252. }
  1253. void SetPostProcessParams( const PostProcessParameters_t *pPostProcessParameters )
  1254. {
  1255. int nSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1256. s_LocalPostProcessParameters[ nSplitScreenSlot ] = *pPostProcessParameters;
  1257. }
  1258. void SetViewFadeParams( byte r, byte g, byte b, byte a, bool bModulate )
  1259. {
  1260. int nSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1261. s_viewFadeColor[ nSplitScreenSlot ].Init( float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, float(a)/255.0f );
  1262. s_bViewFadeModulate[ nSplitScreenSlot ] = bModulate;
  1263. }
  1264. //=====================================================================================================================
  1265. // BloomAdd material proxy ============================================================================================
  1266. //=====================================================================================================================
  1267. class CBloomAddMaterialProxy : public CEntityMaterialProxy
  1268. {
  1269. public:
  1270. CBloomAddMaterialProxy();
  1271. virtual ~CBloomAddMaterialProxy() {}
  1272. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  1273. virtual void OnBind( C_BaseEntity *pEntity );
  1274. virtual IMaterial *GetMaterial();
  1275. private:
  1276. IMaterialVar *m_pMaterialParam_BloomAmount;
  1277. public:
  1278. static void SetBloomAmount( float flBloomAmount ) { s_flBloomAmount = flBloomAmount; }
  1279. private:
  1280. static float s_flBloomAmount;
  1281. };
  1282. float CBloomAddMaterialProxy::s_flBloomAmount = 1.0f;
  1283. CBloomAddMaterialProxy::CBloomAddMaterialProxy()
  1284. : m_pMaterialParam_BloomAmount( NULL )
  1285. {
  1286. }
  1287. bool CBloomAddMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  1288. {
  1289. bool bFoundVar = false;
  1290. m_pMaterialParam_BloomAmount = pMaterial->FindVar( "$c0_x", &bFoundVar, false );
  1291. return true;
  1292. }
  1293. void CBloomAddMaterialProxy::OnBind( C_BaseEntity *pEnt )
  1294. {
  1295. if ( m_pMaterialParam_BloomAmount )
  1296. m_pMaterialParam_BloomAmount->SetFloatValue( s_flBloomAmount );
  1297. }
  1298. IMaterial *CBloomAddMaterialProxy::GetMaterial()
  1299. {
  1300. if ( m_pMaterialParam_BloomAmount == NULL)
  1301. return NULL;
  1302. return m_pMaterialParam_BloomAmount->GetOwningMaterial();
  1303. }
  1304. EXPOSE_MATERIAL_PROXY( CBloomAddMaterialProxy, BloomAdd );
  1305. //=====================================================================================================================
  1306. // Engine_Post material proxy ============================================================================================
  1307. //=====================================================================================================================
  1308. static ConVar mat_software_aa_quality( "mat_software_aa_quality", "0", 0, "Software AA quality mode: (0 - 5-tap filter), (1 - 9-tap filter)" );
  1309. static ConVar mat_software_aa_edge_threshold( "mat_software_aa_edge_threshold", "1.0", 0, "Software AA - adjusts the sensitivity of the software AA shader's edge detection (default 1.0 - a lower value will soften more edges, a higher value will soften fewer)" );
  1310. static ConVar mat_software_aa_blur_one_pixel_lines( "mat_software_aa_blur_one_pixel_lines", "0.5", 0, "How much software AA should blur one-pixel thick lines: (0.0 - none), (1.0 - lots)" );
  1311. static ConVar mat_software_aa_tap_offset( "mat_software_aa_tap_offset", "1.0", 0, "Software AA - adjusts the displacement of the taps used by the software AA shader (default 1.0 - a lower value will make the image sharper, higher will make it blurrier)" );
  1312. static ConVar mat_software_aa_debug( "mat_software_aa_debug", "0", 0, "Software AA debug mode: (0 - off), (1 - show number of 'unlike' samples: 0->black, 1->red, 2->green, 3->blue), (2 - show anti-alias blend strength), (3 - show averaged 'unlike' colour)" );
  1313. static ConVar mat_software_aa_strength_vgui( "mat_software_aa_strength_vgui", "-1.0", 0, "Same as mat_software_aa_strength, but forced to this value when called by the post vgui AA pass." );
  1314. // FXAA convars - defaults taken from 3.11 implementation
  1315. static ConVar mat_fxaa_subpixel_C( "mat_fxaa_subpixel_C", "0.5", 0, "Effects sub-pixel AA quality and inversely sharpness (only used on FXAA Console): (0.33 - sharper), (0.5 - default)" );
  1316. static ConVar mat_fxaa_edge_sharpness_C( "mat_fxaa_edge_sharpness_C", "8.0", 0, "Does not affect PS3 which uses FXAA_CONSOLE_PS3_EDGE_SHARPNESS define due to being ALU bound (and only safe values are 2, 4, 8). On X360, (2.0 - really soft, good for vector graphics inputs), (4.0 - is softer), (8.0 - is sharper, default)" );
  1317. static ConVar mat_fxaa_edge_threshold_C( "mat_fxaa_edge_threshold_C", "0.125", 0, "Does not affect PS3 which uses FXAA_CONSOLE_PS3_EDGE_THRESHOLD define due to being ALU bound (and only safe values are 1/4, 1/8). On X360, (0.125 - default, leaves less aliasing, but is softer, 0.25 - leaves more aliasing and is sharper)" );
  1318. static ConVar mat_fxaa_edge_threshold_min_C( "mat_fxaa_edge_threshold_min_C", "0.0", 0, "Trims the algorithm from processing darks. Does not affect PS3 due to being ALU bound. (0.04 - slower and less aliasing in darks, 0.05 - default, 0.06 - faster but more aliasing in darks). Special note: when using FXAA_GREEN_AS_LUMA likely want to set this to zero" );
  1319. static ConVar mat_fxaa_subpixel_Q( "mat_fxaa_subpixel_Q", "0.75", 0, "Effects sub-pixel AA quality and inversely sharpness (only used on FXAA Quality): (0.0 - off), (1.0 - upper limit, softer), default = 0.75" );
  1320. static ConVar mat_fxaa_edge_threshold_Q( "mat_fxaa_edge_threshold_Q", IsGameConsole() ? "0.166" : ".35", 0, "The minimum amount of local contrast required to apply algorithm: (0.063 - overkill, slower), (0.125 - high quality), (0.166 - default), (0.250 - low quality), (0.333 - too little, faster)" );
  1321. static ConVar mat_fxaa_edge_threshold_min_Q( "mat_fxaa_edge_threshold_min_Q", "0.0", 0, "Trims the algorithm from processing darks: (0.0312 - visible limit, slower), (0.0625 - high quality, faster), (0.0833 - upper limit, the start of fisible unfiltered edges). Special note: when using FXAA_GREEN_AS_LUMA, likely want to set this to zero" );
  1322. class CEnginePostMaterialProxy : public CEntityMaterialProxy
  1323. {
  1324. public:
  1325. CEnginePostMaterialProxy();
  1326. virtual ~CEnginePostMaterialProxy();
  1327. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  1328. virtual void OnBind( C_BaseEntity *pEntity );
  1329. virtual IMaterial *GetMaterial();
  1330. private:
  1331. IMaterialVar *m_pMaterialParam_FXAAValuesC;
  1332. IMaterialVar *m_pMaterialParam_FXAAValuesQ;
  1333. IMaterialVar *m_pMaterialParam_AAValues;
  1334. IMaterialVar *m_pMaterialParam_AAValues2;
  1335. IMaterialVar *m_pMaterialParam_BloomEnable;
  1336. IMaterialVar *m_pMaterialParam_BloomAmount;
  1337. IMaterialVar *m_pMaterialParam_BloomUVTransform;
  1338. IMaterialVar *m_pMaterialParam_ColCorrectEnable;
  1339. IMaterialVar *m_pMaterialParam_ColCorrectNumLookups;
  1340. IMaterialVar *m_pMaterialParam_ColCorrectDefaultWeight;
  1341. IMaterialVar *m_pMaterialParam_ColCorrectLookupWeights;
  1342. IMaterialVar *m_pMaterialParam_LocalContrastStrength;
  1343. IMaterialVar *m_pMaterialParam_LocalContrastEdgeStrength;
  1344. IMaterialVar *m_pMaterialParam_VignetteStart;
  1345. IMaterialVar *m_pMaterialParam_VignetteEnd;
  1346. IMaterialVar *m_pMaterialParam_VignetteBlurEnable;
  1347. IMaterialVar *m_pMaterialParam_VignetteBlurStrength;
  1348. IMaterialVar *m_pMaterialParam_FadeToBlackStrength;
  1349. IMaterialVar *m_pMaterialParam_DepthBlurFocalDistance;
  1350. IMaterialVar *m_pMaterialParam_DepthBlurStrength;
  1351. IMaterialVar *m_pMaterialParam_ScreenBlurStrength;
  1352. IMaterialVar *m_pMaterialParam_FilmGrainStrength;
  1353. IMaterialVar *m_pMaterialParam_VomitEnable;
  1354. IMaterialVar *m_pMaterialParam_VomitColor1;
  1355. IMaterialVar *m_pMaterialParam_VomitColor2;
  1356. IMaterialVar *m_pMaterialParam_FadeColor;
  1357. IMaterialVar *m_pMaterialParam_FadeType;
  1358. public:
  1359. static void SetupEnginePostMaterial( const Vector4D & fullViewportBloomUVs, const Vector4D & fullViewportFBUVs, const Vector2D & destTexSize,
  1360. bool bPerformSoftwareAA, bool bPerformBloom, bool bPerformColCorrect, float flAAStrength, float flBloomAmount );
  1361. static void SetupEnginePostMaterialAA( bool bPerformSoftwareAA, float flAAStrength );
  1362. static void SetupEnginePostMaterialTextureTransform( const Vector4D & fullViewportBloomUVs, const Vector4D & fullViewportFBUVs, Vector2D destTexSize );
  1363. #if defined(_PS3)
  1364. static IMaterial *GetEnginePostMaterial( IMaterialSystem * materials );
  1365. static int GetLocalContrastEnable( IMaterialSystem * materials );
  1366. static ITexture *GetSrcTexture( IMaterialSystem * materials );
  1367. static ITexture *GetSrcPS3Texture( IMaterialSystem * materials );
  1368. static ITexture *GetDstRT0Texture( IMaterialSystem * materials );
  1369. static ITexture *GetDstRT1Texture( IMaterialSystem * materials );
  1370. #endif
  1371. private:
  1372. static float s_vBloomAAValues[4];
  1373. static float s_vBloomAAValues2[4];
  1374. static float s_vFXAAValuesC[4];
  1375. static float s_vFXAAValuesQ[4];
  1376. static float s_vBloomUVTransform[4];
  1377. static int s_PostBloomEnable;
  1378. static float s_PostBloomAmount;
  1379. #if defined(_PS3)
  1380. static IMaterial *s_pEnginePostMaterial;
  1381. static ITexture *s_pSrcTexture;
  1382. static ITexture *s_pSrcPS3Texture;
  1383. static ITexture *s_pDstRT0Texture;
  1384. static ITexture *s_pDstRT1Texture;
  1385. static IMaterialVar *s_pMaterialParam_LocalContrastEnable;
  1386. #endif
  1387. };
  1388. float CEnginePostMaterialProxy::s_vBloomAAValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  1389. float CEnginePostMaterialProxy::s_vBloomAAValues2[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  1390. float CEnginePostMaterialProxy::s_vFXAAValuesC[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  1391. float CEnginePostMaterialProxy::s_vFXAAValuesQ[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  1392. float CEnginePostMaterialProxy::s_vBloomUVTransform[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  1393. int CEnginePostMaterialProxy::s_PostBloomEnable = 1;
  1394. float CEnginePostMaterialProxy::s_PostBloomAmount = 1.0f;
  1395. #if defined(_PS3)
  1396. IMaterial *CEnginePostMaterialProxy::s_pEnginePostMaterial = NULL;
  1397. ITexture *CEnginePostMaterialProxy::s_pSrcTexture = NULL;
  1398. ITexture *CEnginePostMaterialProxy::s_pSrcPS3Texture = NULL;
  1399. ITexture *CEnginePostMaterialProxy::s_pDstRT0Texture = NULL;
  1400. ITexture *CEnginePostMaterialProxy::s_pDstRT1Texture = NULL;
  1401. IMaterialVar *CEnginePostMaterialProxy::s_pMaterialParam_LocalContrastEnable = NULL;
  1402. #endif
  1403. CEnginePostMaterialProxy::CEnginePostMaterialProxy()
  1404. {
  1405. m_pMaterialParam_FXAAValuesC = NULL;
  1406. m_pMaterialParam_FXAAValuesQ = NULL;
  1407. m_pMaterialParam_AAValues = NULL;
  1408. m_pMaterialParam_AAValues2 = NULL;
  1409. m_pMaterialParam_BloomUVTransform = NULL;
  1410. m_pMaterialParam_BloomEnable = NULL;
  1411. m_pMaterialParam_BloomAmount = NULL;
  1412. m_pMaterialParam_ColCorrectEnable = NULL;
  1413. m_pMaterialParam_ColCorrectNumLookups = NULL;
  1414. m_pMaterialParam_ColCorrectDefaultWeight = NULL;
  1415. m_pMaterialParam_ColCorrectLookupWeights = NULL;
  1416. m_pMaterialParam_LocalContrastStrength = NULL;
  1417. m_pMaterialParam_LocalContrastEdgeStrength = NULL;
  1418. m_pMaterialParam_VignetteStart = NULL;
  1419. m_pMaterialParam_VignetteEnd = NULL;
  1420. m_pMaterialParam_VignetteBlurEnable = NULL;
  1421. m_pMaterialParam_VignetteBlurStrength = NULL;
  1422. m_pMaterialParam_FadeToBlackStrength = NULL;
  1423. m_pMaterialParam_DepthBlurFocalDistance = NULL;
  1424. m_pMaterialParam_DepthBlurStrength = NULL;
  1425. m_pMaterialParam_ScreenBlurStrength = NULL;
  1426. m_pMaterialParam_FilmGrainStrength = NULL;
  1427. #if defined(_PS3)
  1428. s_pMaterialParam_LocalContrastEnable = NULL;
  1429. s_pEnginePostMaterial = NULL;
  1430. s_pSrcTexture = NULL;
  1431. s_pSrcPS3Texture = NULL;
  1432. s_pDstRT0Texture = NULL;
  1433. s_pDstRT1Texture = NULL;
  1434. #endif
  1435. }
  1436. CEnginePostMaterialProxy::~CEnginePostMaterialProxy()
  1437. {
  1438. // Do nothing
  1439. }
  1440. bool CEnginePostMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  1441. {
  1442. bool bFoundVar = false;
  1443. m_pMaterialParam_FXAAValuesC = pMaterial->FindVar( "$FXAAInternalC", &bFoundVar, false );
  1444. m_pMaterialParam_FXAAValuesQ = pMaterial->FindVar( "$FXAAInternalQ", &bFoundVar, false );
  1445. m_pMaterialParam_AAValues = pMaterial->FindVar( "$AAInternal1", &bFoundVar, false );
  1446. m_pMaterialParam_AAValues2 = pMaterial->FindVar( "$AAInternal3", &bFoundVar, false );
  1447. m_pMaterialParam_BloomUVTransform = pMaterial->FindVar( "$AAInternal2", &bFoundVar, false );
  1448. m_pMaterialParam_BloomEnable = pMaterial->FindVar( "$bloomEnable", &bFoundVar, false );
  1449. m_pMaterialParam_BloomAmount = pMaterial->FindVar( "$bloomAmount", &bFoundVar, false );
  1450. m_pMaterialParam_ColCorrectEnable = pMaterial->FindVar( "$colCorrectEnable", &bFoundVar, false );
  1451. m_pMaterialParam_ColCorrectNumLookups = pMaterial->FindVar( "$colCorrect_NumLookups", &bFoundVar, false );
  1452. m_pMaterialParam_ColCorrectDefaultWeight = pMaterial->FindVar( "$colCorrect_DefaultWeight", &bFoundVar, false );
  1453. m_pMaterialParam_ColCorrectLookupWeights = pMaterial->FindVar( "$colCorrect_LookupWeights", &bFoundVar, false );
  1454. m_pMaterialParam_LocalContrastStrength = pMaterial->FindVar( "$localContrastScale", &bFoundVar, false );
  1455. m_pMaterialParam_LocalContrastEdgeStrength = pMaterial->FindVar( "$localContrastEdgeScale", &bFoundVar, false );
  1456. m_pMaterialParam_VignetteStart = pMaterial->FindVar( "$localContrastVignetteStart", &bFoundVar, false );
  1457. m_pMaterialParam_VignetteEnd = pMaterial->FindVar( "$localContrastVignetteEnd", &bFoundVar, false );
  1458. m_pMaterialParam_VignetteBlurEnable = pMaterial->FindVar( "$blurredVignetteEnable", &bFoundVar, false );
  1459. m_pMaterialParam_VignetteBlurStrength = pMaterial->FindVar( "$blurredVignetteScale", &bFoundVar, false );
  1460. m_pMaterialParam_FadeToBlackStrength = pMaterial->FindVar( "$fadeToBlackScale", &bFoundVar, false );
  1461. m_pMaterialParam_DepthBlurFocalDistance = pMaterial->FindVar( "$depthBlurFocalDistance", &bFoundVar, false );
  1462. m_pMaterialParam_DepthBlurStrength = pMaterial->FindVar( "$depthBlurStrength", &bFoundVar, false );
  1463. m_pMaterialParam_ScreenBlurStrength = pMaterial->FindVar( "$screenBlurStrength", &bFoundVar, false );
  1464. m_pMaterialParam_FilmGrainStrength = pMaterial->FindVar( "$noiseScale", &bFoundVar, false );
  1465. m_pMaterialParam_VomitEnable = pMaterial->FindVar( "$vomitEnable", &bFoundVar, false );
  1466. m_pMaterialParam_VomitColor1 = pMaterial->FindVar( "$vomitColor1", &bFoundVar, false );
  1467. m_pMaterialParam_VomitColor2 = pMaterial->FindVar( "$vomitColor2", &bFoundVar, false );
  1468. m_pMaterialParam_FadeColor = pMaterial->FindVar( "$fadeColor", &bFoundVar, false );
  1469. m_pMaterialParam_FadeType = pMaterial->FindVar( "$fade", &bFoundVar, false );
  1470. #if defined(_PS3)
  1471. s_pEnginePostMaterial = NULL;
  1472. s_pSrcTexture = NULL;
  1473. s_pSrcPS3Texture = NULL;
  1474. s_pDstRT0Texture = NULL;
  1475. s_pDstRT1Texture = NULL;
  1476. s_pMaterialParam_LocalContrastEnable = NULL;
  1477. #endif
  1478. return true;
  1479. }
  1480. void CEnginePostMaterialProxy::OnBind( C_BaseEntity *pEnt )
  1481. {
  1482. int nSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1483. if ( m_pMaterialParam_FXAAValuesC )
  1484. m_pMaterialParam_FXAAValuesC->SetVecValue( s_vFXAAValuesC, 4 );
  1485. if ( m_pMaterialParam_FXAAValuesQ )
  1486. m_pMaterialParam_FXAAValuesQ->SetVecValue( s_vFXAAValuesQ, 4 );
  1487. if ( m_pMaterialParam_AAValues )
  1488. m_pMaterialParam_AAValues->SetVecValue( s_vBloomAAValues, 4 );
  1489. if ( m_pMaterialParam_AAValues2 )
  1490. m_pMaterialParam_AAValues2->SetVecValue( s_vBloomAAValues2, 4 );
  1491. if ( m_pMaterialParam_BloomUVTransform )
  1492. m_pMaterialParam_BloomUVTransform->SetVecValue( s_vBloomUVTransform, 4 );
  1493. if ( m_pMaterialParam_BloomEnable )
  1494. m_pMaterialParam_BloomEnable->SetIntValue( s_PostBloomEnable );
  1495. if ( m_pMaterialParam_BloomAmount )
  1496. m_pMaterialParam_BloomAmount->SetFloatValue( s_PostBloomAmount );
  1497. if ( m_pMaterialParam_LocalContrastStrength )
  1498. m_pMaterialParam_LocalContrastStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_LOCAL_CONTRAST_STRENGTH ] );
  1499. if ( m_pMaterialParam_LocalContrastEdgeStrength )
  1500. m_pMaterialParam_LocalContrastEdgeStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_LOCAL_CONTRAST_EDGE_STRENGTH ] );
  1501. if ( m_pMaterialParam_VignetteStart )
  1502. m_pMaterialParam_VignetteStart->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_VIGNETTE_START ] );
  1503. if ( m_pMaterialParam_VignetteEnd )
  1504. m_pMaterialParam_VignetteEnd->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_VIGNETTE_END ] );
  1505. if ( m_pMaterialParam_VignetteBlurEnable )
  1506. m_pMaterialParam_VignetteBlurEnable->SetIntValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_VIGNETTE_BLUR_STRENGTH ] > 0.0f ? 1 : 0 );
  1507. if ( m_pMaterialParam_VignetteBlurStrength )
  1508. m_pMaterialParam_VignetteBlurStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_VIGNETTE_BLUR_STRENGTH ] );
  1509. if ( m_pMaterialParam_FadeToBlackStrength )
  1510. m_pMaterialParam_FadeToBlackStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_FADE_TO_BLACK_STRENGTH ] );
  1511. if ( m_pMaterialParam_DepthBlurFocalDistance )
  1512. m_pMaterialParam_DepthBlurFocalDistance->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_DEPTH_BLUR_FOCAL_DISTANCE ] );
  1513. if ( m_pMaterialParam_DepthBlurStrength )
  1514. m_pMaterialParam_DepthBlurStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_DEPTH_BLUR_STRENGTH ] );
  1515. if ( m_pMaterialParam_ScreenBlurStrength )
  1516. m_pMaterialParam_ScreenBlurStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_SCREEN_BLUR_STRENGTH ] );
  1517. if ( m_pMaterialParam_FilmGrainStrength )
  1518. m_pMaterialParam_FilmGrainStrength->SetFloatValue( s_LocalPostProcessParameters[ nSplitScreenSlot ].m_flParameters[ PPPN_FILM_GRAIN_STRENGTH ] );
  1519. #ifdef PORTAL2
  1520. const C_Portal_Player* pLocalPlayer = C_Portal_Player::GetLocalPortalPlayer();
  1521. const bool bScreenSpacePaintEffectIsActive = pLocalPlayer && pLocalPlayer->ScreenSpacePaintEffectIsActive();
  1522. if ( m_pMaterialParam_VomitEnable )
  1523. {
  1524. m_pMaterialParam_VomitEnable->SetIntValue( bScreenSpacePaintEffectIsActive ? 1 : 0 );
  1525. }
  1526. if ( bScreenSpacePaintEffectIsActive && m_pMaterialParam_VomitColor1 && m_pMaterialParam_VomitColor2 )
  1527. {
  1528. pLocalPlayer->SetScreenSpacePaintEffectColors( m_pMaterialParam_VomitColor1, m_pMaterialParam_VomitColor2 );
  1529. }
  1530. #endif
  1531. if ( m_pMaterialParam_FadeType )
  1532. {
  1533. int nFadeType = ( s_bViewFadeModulate[nSplitScreenSlot] ) ? 2 : 1;
  1534. nFadeType = ( s_viewFadeColor[nSplitScreenSlot][3] > 0.0f ) ? nFadeType : 0;
  1535. m_pMaterialParam_FadeType->SetIntValue( nFadeType );
  1536. }
  1537. if ( m_pMaterialParam_FadeColor )
  1538. {
  1539. m_pMaterialParam_FadeColor->SetVecValue( s_viewFadeColor[nSplitScreenSlot].Base(), 4 );
  1540. }
  1541. }
  1542. IMaterial *CEnginePostMaterialProxy::GetMaterial()
  1543. {
  1544. if ( m_pMaterialParam_AAValues == NULL)
  1545. return NULL;
  1546. return m_pMaterialParam_AAValues->GetOwningMaterial();
  1547. }
  1548. #if defined(_PS3 )
  1549. IMaterial *CEnginePostMaterialProxy::GetEnginePostMaterial( IMaterialSystem * materials )
  1550. {
  1551. if( s_pEnginePostMaterial == NULL)
  1552. {
  1553. s_pEnginePostMaterial = materials->FindMaterial( "dev/engine_post", TEXTURE_GROUP_OTHER, true );
  1554. }
  1555. return s_pEnginePostMaterial;
  1556. }
  1557. int CEnginePostMaterialProxy::GetLocalContrastEnable( IMaterialSystem * materials )
  1558. {
  1559. if( s_pMaterialParam_LocalContrastEnable == NULL )
  1560. {
  1561. s_pMaterialParam_LocalContrastEnable = GetEnginePostMaterial( materials )->FindVar( "$localcontrastenable", NULL, false );
  1562. }
  1563. return s_pMaterialParam_LocalContrastEnable->GetIntValueFast();
  1564. }
  1565. ITexture *CEnginePostMaterialProxy::GetSrcTexture( IMaterialSystem * materials )
  1566. {
  1567. if( s_pSrcTexture == NULL )
  1568. {
  1569. s_pSrcTexture = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  1570. }
  1571. return s_pSrcTexture;
  1572. }
  1573. ITexture *CEnginePostMaterialProxy::GetSrcPS3Texture( IMaterialSystem * materials )
  1574. {
  1575. if( s_pSrcPS3Texture == NULL )
  1576. {
  1577. s_pSrcPS3Texture = materials->FindTexture( "^PS3^BACKBUFFER", TEXTURE_GROUP_RENDER_TARGET );
  1578. }
  1579. return s_pSrcPS3Texture;
  1580. }
  1581. ITexture *CEnginePostMaterialProxy::GetDstRT0Texture( IMaterialSystem * materials )
  1582. {
  1583. if( s_pDstRT0Texture == NULL )
  1584. {
  1585. s_pDstRT0Texture = materials->FindTexture( "_rt_SmallFB0", TEXTURE_GROUP_RENDER_TARGET );
  1586. }
  1587. return s_pDstRT0Texture;
  1588. }
  1589. ITexture *CEnginePostMaterialProxy::GetDstRT1Texture( IMaterialSystem * materials )
  1590. {
  1591. if( s_pDstRT1Texture == NULL )
  1592. {
  1593. s_pDstRT1Texture = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  1594. }
  1595. return s_pDstRT1Texture;
  1596. }
  1597. #endif
  1598. void CEnginePostMaterialProxy::SetupEnginePostMaterialAA( bool bPerformSoftwareAA, float flAAStrength )
  1599. {
  1600. if ( bPerformSoftwareAA )
  1601. {
  1602. // Pass ConVars to the material by proxy
  1603. // FXAA
  1604. // Console
  1605. s_vFXAAValuesC[0] = mat_fxaa_subpixel_C.GetFloat();
  1606. s_vFXAAValuesC[1] = mat_fxaa_edge_sharpness_C.GetFloat();
  1607. s_vFXAAValuesC[2] = mat_fxaa_edge_threshold_C.GetFloat();
  1608. s_vFXAAValuesC[3] = mat_fxaa_edge_threshold_min_C.GetFloat();
  1609. // Quality
  1610. s_vFXAAValuesQ[0] = mat_fxaa_subpixel_Q.GetFloat();
  1611. s_vFXAAValuesC[1] = 0.0f; // unused
  1612. s_vFXAAValuesQ[2] = mat_fxaa_edge_threshold_Q.GetFloat();
  1613. s_vFXAAValuesC[3] = mat_fxaa_edge_threshold_min_Q.GetFloat();
  1614. // Software AA (old)
  1615. // - the strength of the AA effect (from 0 to 1)
  1616. // - how much to allow 1-pixel lines to be blurred (from 0 to 1)
  1617. // - pick one of the two quality modes (5-tap or 9-tap filter)
  1618. // - optionally enable one of several debug modes (via dynamic combos)
  1619. // NOTE: this order matches pixel shader constants in Engine_Post_ps2x.fxc
  1620. s_vBloomAAValues[0] = flAAStrength;
  1621. s_vBloomAAValues[1] = 1.0f - mat_software_aa_blur_one_pixel_lines.GetFloat();
  1622. s_vBloomAAValues[2] = mat_software_aa_quality.GetInt();
  1623. s_vBloomAAValues[3] = mat_software_aa_debug.GetInt();
  1624. s_vBloomAAValues2[0] = mat_software_aa_edge_threshold.GetFloat();
  1625. s_vBloomAAValues2[1] = mat_software_aa_tap_offset.GetFloat();
  1626. //s_vBloomAAValues2[2] = unused;
  1627. //s_vBloomAAValues2[3] = unused;
  1628. }
  1629. else
  1630. {
  1631. // Zero-strength AA is interpreted as "AA disabled"
  1632. s_vBloomAAValues[0] = 0.0f;
  1633. }
  1634. }
  1635. void CEnginePostMaterialProxy::SetupEnginePostMaterialTextureTransform( const Vector4D & fullViewportBloomUVs, const Vector4D & fullViewportFBUVs, Vector2D fbSize )
  1636. {
  1637. // Engine_Post uses a UV transform (from (quarter-res) bloom texture coords ('1')
  1638. // to (full-res) framebuffer texture coords ('2')).
  1639. //
  1640. // We compute the UV transform as an offset and a scale, using the texture coordinates
  1641. // of the top-left corner of the screen to compute the offset and the coordinate
  1642. // change from the top-left to the bottom-right of the quad to compute the scale.
  1643. // Take texel coordinates (start = top-left, end = bottom-right):
  1644. Vector2D texelStart1 = Vector2D( fullViewportBloomUVs.x, fullViewportBloomUVs.y );
  1645. Vector2D texelStart2 = Vector2D( fullViewportFBUVs.x, fullViewportFBUVs.y );
  1646. Vector2D texelEnd1 = Vector2D( fullViewportBloomUVs.z, fullViewportBloomUVs.w );
  1647. Vector2D texelEnd2 = Vector2D( fullViewportFBUVs.z, fullViewportFBUVs.w );
  1648. // ...and transform to UV coordinates:
  1649. Vector2D texRes1 = fbSize / 4;
  1650. Vector2D texRes2 = fbSize;
  1651. Vector2D uvStart1 = ( texelStart1 + Vector2D(0.5,0.5) ) / texRes1;
  1652. Vector2D uvStart2 = ( texelStart2 + Vector2D(0.5,0.5) ) / texRes2;
  1653. Vector2D dUV1 = ( texelEnd1 - texelStart1 ) / texRes1;
  1654. Vector2D dUV2 = ( texelEnd2 - texelStart2 ) / texRes2;
  1655. // We scale about the rect's top-left pixel centre (not the origin) in UV-space:
  1656. // uv' = ((uv - uvStart1)*uvScale + uvStart1) + uvOffset
  1657. // = uvScale*uv + uvOffset + uvStart1*(1 - uvScale)
  1658. Vector2D uvOffset = uvStart2 - uvStart1;
  1659. Vector2D uvScale = dUV2 / dUV1;
  1660. uvOffset = uvOffset + uvStart1*(Vector2D(1,1) - uvScale);
  1661. s_vBloomUVTransform[0] = uvOffset.x;
  1662. s_vBloomUVTransform[1] = uvOffset.y;
  1663. s_vBloomUVTransform[2] = uvScale.x;
  1664. s_vBloomUVTransform[3] = uvScale.y;
  1665. }
  1666. void CEnginePostMaterialProxy::SetupEnginePostMaterial( const Vector4D & fullViewportBloomUVs, const Vector4D & fullViewportFBUVs, const Vector2D & destTexSize,
  1667. bool bPerformSoftwareAA, bool bPerformBloom, bool bPerformColCorrect, float flAAStrength, float flBloomAmount )
  1668. {
  1669. s_PostBloomEnable = bPerformBloom ? 1 : 0;
  1670. s_PostBloomAmount = flBloomAmount;
  1671. SetupEnginePostMaterialAA( bPerformSoftwareAA, flAAStrength );
  1672. SetupEnginePostMaterialTextureTransform( fullViewportBloomUVs, fullViewportFBUVs, destTexSize );
  1673. }
  1674. EXPOSE_MATERIAL_PROXY( CEnginePostMaterialProxy, engine_post );
  1675. static void DrawBloomDebugBoxes( IMatRenderContext *pRenderContext, int nX, int nY, int nWidth, int nHeight )
  1676. {
  1677. // draw inset rects which should have a centered bloom
  1678. pRenderContext->PushRenderTargetAndViewport();
  1679. pRenderContext->SetRenderTarget( IsPS3() ? materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET ) : NULL );
  1680. // full screen clear
  1681. pRenderContext->Viewport( nX, nY, nWidth, nHeight );
  1682. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1683. pRenderContext->ClearBuffers( true, true );
  1684. // inset for screensafe
  1685. int inset = 64;
  1686. int size = 32;
  1687. // centerish, translating
  1688. static int wx = 0;
  1689. wx = ( wx + 1 ) & 63;
  1690. pRenderContext->Viewport( nWidth / 2 + nX + wx, nY + nHeight / 2, size, size );
  1691. pRenderContext->ClearColor3ub( 255, 255, 255 );
  1692. pRenderContext->ClearBuffers( true, true );
  1693. // upper left
  1694. pRenderContext->Viewport( nX + inset, nY + inset, size, size );
  1695. pRenderContext->ClearBuffers( true, true );
  1696. // upper right
  1697. pRenderContext->Viewport( nX + nWidth - inset - size, nY + inset, size, size );
  1698. pRenderContext->ClearBuffers( true, true );
  1699. // lower right
  1700. pRenderContext->Viewport( nX + nWidth - inset - size, nY + nHeight - inset - size, size, size );
  1701. pRenderContext->ClearBuffers( true, true );
  1702. // lower left
  1703. pRenderContext->Viewport( nX + inset, nX + nHeight - inset - size, size, size );
  1704. pRenderContext->ClearBuffers( true, true );
  1705. // restore
  1706. pRenderContext->PopRenderTargetAndViewport();
  1707. }
  1708. static float GetBloomAmount( void )
  1709. {
  1710. HDRType_t hdrType = g_pMaterialSystemHardwareConfig->GetHDRType();
  1711. bool bBloomEnabled = (mat_hdr_level.GetInt() >= 1);
  1712. if ( !engine->MapHasHDRLighting() )
  1713. bBloomEnabled = false;
  1714. if ( mat_force_bloom.GetInt() )
  1715. bBloomEnabled = true;
  1716. if ( mat_disable_bloom.GetInt() )
  1717. bBloomEnabled = false;
  1718. if ( building_cubemaps.GetBool() )
  1719. bBloomEnabled = false;
  1720. if ( mat_fullbright.GetInt() == 1 )
  1721. {
  1722. bBloomEnabled = false;
  1723. }
  1724. float flBloomAmount=0.0;
  1725. if (bBloomEnabled)
  1726. {
  1727. static float currentBloomAmount = 1.0f;
  1728. float rate = mat_bloomamount_rate.GetFloat();
  1729. // Use the appropriate bloom scale settings. Mapmakers's overrides the convar settings.
  1730. currentBloomAmount = GetCurrentBloomScale() * rate + ( 1.0f - rate ) * currentBloomAmount;
  1731. flBloomAmount = currentBloomAmount;
  1732. if (IsGameConsole())
  1733. {
  1734. //we want to scale the bloom effect down because the effect textures are lower reolution on the 360.
  1735. //target match 1280x1024
  1736. if ( (g_pMaterialSystem->GetCurrentConfigForVideoCard().m_VideoMode.m_Height == 720) )
  1737. {
  1738. flBloomAmount *= (720.0f/1024.0f);
  1739. }
  1740. else //640x480
  1741. {
  1742. flBloomAmount *= (480.0f/1024.0f);
  1743. }
  1744. }
  1745. }
  1746. if ( hdrType == HDR_TYPE_NONE )
  1747. {
  1748. flBloomAmount *= mat_non_hdr_bloom_scalefactor.GetFloat();
  1749. }
  1750. flBloomAmount *= mat_bloom_scalefactor_scalar.GetFloat();
  1751. return flBloomAmount;
  1752. }
  1753. // Control for dumping render targets to files for debugging
  1754. static ConVar mat_dump_rts( "mat_dump_rts", "0", FCVAR_DEVELOPMENTONLY );
  1755. static bool s_bDumpRenderTargets = false;
  1756. static int s_nRTIndex = 0;
  1757. // Dump a rendertarget to a TGA. Useful for looking at intermediate render target results.
  1758. static void DumpTGAofRenderTarget( const int width, const int height, const char *pFilename )
  1759. {
  1760. // Ensure that mat_queue_mode is zero...this ConVarRef lookup isn't cheap, but this is rarely-run debug code
  1761. ConVarRef mat_queue_mode( "mat_queue_mode" );
  1762. if ( mat_queue_mode.GetInt() != 0 )
  1763. {
  1764. DevMsg( "Error: mat_queue_mode must be 0 to dump debug rendertargets\n" );
  1765. mat_dump_rts.SetValue( 0 ); // Just report this error once and stop trying to dump images
  1766. return;
  1767. }
  1768. CMatRenderContextPtr pRenderContext( materials );
  1769. // Get the data from the render target and save to disk bitmap bits
  1770. unsigned char *pImage = ( unsigned char * )malloc( width * 4 * height );
  1771. // Get Bits from the material system
  1772. pRenderContext->ReadPixels( 0, 0, width, height, pImage, IMAGE_FORMAT_RGBA8888 );
  1773. // allocate a buffer to write the tga into
  1774. int iMaxTGASize = 1024 + (width * height * 4);
  1775. void *pTGA = malloc( iMaxTGASize );
  1776. CUtlBuffer buffer( pTGA, iMaxTGASize );
  1777. if( !TGAWriter::WriteToBuffer( pImage, buffer, width, height, IMAGE_FORMAT_RGBA8888, IMAGE_FORMAT_RGBA8888 ) )
  1778. {
  1779. Error( "Couldn't write bitmap data snapshot.\n" );
  1780. }
  1781. free( pImage );
  1782. // async write to disk (this will take ownership of the memory)
  1783. char szPathedFileName[_MAX_PATH];
  1784. Q_snprintf( szPathedFileName, sizeof(szPathedFileName), "//MOD/%d_%s_%s.tga", s_nRTIndex++, pFilename, IsOSX() ? "OSX" : "PC" );
  1785. FileHandle_t fileTGA = filesystem->Open( szPathedFileName, "wb" );
  1786. filesystem->Write( buffer.Base(), buffer.TellPut(), fileTGA );
  1787. filesystem->Close( fileTGA );
  1788. free( pTGA );
  1789. }
  1790. static bool s_bScreenEffectTextureIsUpdated = false;
  1791. // WARNING: This function sets rendertarget and viewport. Save and restore is left to the caller.
  1792. static void DownsampleFBQuarterSize( IMatRenderContext *pRenderContext, int nSrcWidth, int nSrcHeight, ITexture* pDest,
  1793. bool bFloatHDR = false )
  1794. {
  1795. Assert( pRenderContext );
  1796. Assert( pDest );
  1797. // *Everything* in here relies on the small RTs being exactly 1/4 the full FB res
  1798. Assert( pDest->GetActualWidth() == nSrcWidth / 4 );
  1799. Assert( pDest->GetActualHeight() == nSrcHeight / 4 );
  1800. IMaterial *downsample_mat;
  1801. #if defined(_PS3)
  1802. if( mat_PS3_findpostvarsfast.GetInt() )
  1803. {
  1804. downsample_mat = CDownsampleMaterialProxy::GetDownsampleMaterial( materials );
  1805. CDownsampleMaterialProxy::SetupDownsampleMaterial( g_flBloomExponent, g_flBloomSaturation );
  1806. }
  1807. else
  1808. #endif
  1809. {
  1810. downsample_mat = materials->FindMaterial( bFloatHDR ? "dev/downsample" : "dev/downsample_non_hdr", TEXTURE_GROUP_OTHER, true );
  1811. bool bFound;
  1812. IMaterialVar *pbloomexpvar = downsample_mat->FindVar( "$bloomexp", &bFound, false );
  1813. if ( bFound )
  1814. {
  1815. pbloomexpvar->SetFloatValue( g_flBloomExponent );
  1816. }
  1817. IMaterialVar *pbloomsaturationvar = downsample_mat->FindVar( "$bloomsaturation", &bFound, false );
  1818. if ( bFound )
  1819. {
  1820. pbloomsaturationvar->SetFloatValue( g_flBloomSaturation );
  1821. }
  1822. }
  1823. // downsample fb to rt0
  1824. SetRenderTargetAndViewPort( pDest );
  1825. // note the -2's below. Thats because we are downsampling on each axis and the shader
  1826. // accesses pixels on both sides of the source coord
  1827. pRenderContext->DrawScreenSpaceRectangle( downsample_mat, 0, 0, nSrcWidth/4, nSrcHeight/4,
  1828. 0, 0, nSrcWidth-2, nSrcHeight-2,
  1829. nSrcWidth, nSrcHeight );
  1830. if ( IsX360() )
  1831. {
  1832. pRenderContext->CopyRenderTargetToTextureEx( pDest, 0, NULL, NULL );
  1833. }
  1834. else if ( s_bDumpRenderTargets )
  1835. {
  1836. DumpTGAofRenderTarget( nSrcWidth/4, nSrcHeight/4, "QuarterSizeFB" );
  1837. }
  1838. }
  1839. static void Generate8BitBloomTexture( IMatRenderContext *pRenderContext,
  1840. int x, int y, int w, int h, bool bExtractBloomRange, bool bClearRGB = true )
  1841. {
  1842. pRenderContext->PushRenderTargetAndViewport();
  1843. ITexture *pSrc;
  1844. IMaterial *xblur_mat;
  1845. IMaterial *yblur_mat;
  1846. ITexture *dest_rt0;
  1847. ITexture *dest_rt1;
  1848. #if defined(_PS3)
  1849. if( mat_PS3_findpostvarsfast.GetInt() )
  1850. {
  1851. pSrc = CEnginePostMaterialProxy::GetSrcTexture( materials );
  1852. // FIXME: assumes bClearRGB = false here
  1853. xblur_mat = CXBlurMaterialProxy::GetXBlurMaterial( materials );
  1854. yblur_mat = CYBlurMaterialProxy::GetYBlurMaterial( materials );
  1855. dest_rt0 = CEnginePostMaterialProxy::GetDstRT0Texture( materials );
  1856. dest_rt1 = CEnginePostMaterialProxy::GetDstRT1Texture( materials );
  1857. }
  1858. else
  1859. #endif
  1860. {
  1861. pSrc = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  1862. xblur_mat = materials->FindMaterial( "dev/blurfilterx_nohdr", TEXTURE_GROUP_OTHER, true );
  1863. yblur_mat = NULL;
  1864. if ( bClearRGB )
  1865. {
  1866. yblur_mat = materials->FindMaterial( "dev/blurfiltery_nohdr_clear", TEXTURE_GROUP_OTHER, true );
  1867. }
  1868. else
  1869. {
  1870. yblur_mat = materials->FindMaterial( "dev/blurfiltery_nohdr", TEXTURE_GROUP_OTHER, true );
  1871. }
  1872. dest_rt0 = materials->FindTexture( "_rt_SmallFB0", TEXTURE_GROUP_RENDER_TARGET );
  1873. dest_rt1 = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  1874. }
  1875. int nSrcWidth = pSrc->GetActualWidth();
  1876. int nSrcHeight = pSrc->GetActualHeight(); //,nViewportHeight;
  1877. // *Everything* in here relies on the small RTs being exactly 1/4 the full FB res
  1878. Assert( dest_rt0->GetActualWidth() == pSrc->GetActualWidth() / 4 );
  1879. Assert( dest_rt0->GetActualHeight() == pSrc->GetActualHeight() / 4 );
  1880. Assert( dest_rt1->GetActualWidth() == pSrc->GetActualWidth() / 4 );
  1881. Assert( dest_rt1->GetActualHeight() == pSrc->GetActualHeight() / 4 );
  1882. // downsample fb to rt0
  1883. if ( bExtractBloomRange )
  1884. {
  1885. DownsampleFBQuarterSize( pRenderContext, nSrcWidth, nSrcHeight, dest_rt0 );
  1886. }
  1887. else
  1888. {
  1889. // just downsample, don't apply bloom extraction math
  1890. DownsampleFBQuarterSize( pRenderContext, nSrcWidth, nSrcHeight, dest_rt0, true );
  1891. }
  1892. // Gaussian blur x rt0 to rt1
  1893. SetRenderTargetAndViewPort( dest_rt1 );
  1894. pRenderContext->DrawScreenSpaceRectangle( xblur_mat, 0, 0, nSrcWidth/4, nSrcHeight/4,
  1895. 0, 0, nSrcWidth/4-1, nSrcHeight/4-1,
  1896. nSrcWidth/4, nSrcHeight/4 );
  1897. if ( IsX360() )
  1898. {
  1899. pRenderContext->CopyRenderTargetToTextureEx( dest_rt1, 0, NULL, NULL );
  1900. }
  1901. else if ( s_bDumpRenderTargets )
  1902. {
  1903. DumpTGAofRenderTarget( nSrcWidth/4, nSrcHeight/4, "BlurX" );
  1904. }
  1905. // Gaussian blur y rt1 to rt0
  1906. SetRenderTargetAndViewPort( dest_rt0 );
  1907. IMaterialVar *pBloomAmountVar = yblur_mat->FindVar( "$bloomamount", NULL );
  1908. pBloomAmountVar->SetFloatValue( 1.0f ); // the bloom amount is now applied in engine_post or bloomadd materials
  1909. pRenderContext->DrawScreenSpaceRectangle( yblur_mat, 0, 0, nSrcWidth / 4, nSrcHeight / 4,
  1910. 0, 0, nSrcWidth / 4 - 1, nSrcHeight / 4 - 1,
  1911. nSrcWidth / 4, nSrcHeight / 4 );
  1912. if ( IsX360() )
  1913. {
  1914. pRenderContext->CopyRenderTargetToTextureEx( dest_rt0, 0, NULL, NULL );
  1915. }
  1916. else if ( s_bDumpRenderTargets )
  1917. {
  1918. DumpTGAofRenderTarget( nSrcWidth/4, nSrcHeight/4, "BlurYAndBloom" );
  1919. }
  1920. pRenderContext->PopRenderTargetAndViewport();
  1921. }
  1922. static void DoTonemapping( IMatRenderContext *pRenderContext, int nX, int nY, int nWidth, int nHeight, float flAutoExposureMin, float flAutoExposureMax )
  1923. {
  1924. // Skip if HDR disabled
  1925. if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE )
  1926. return;
  1927. // Update HDR histogram
  1928. if ( mat_dynamic_tonemapping.GetInt() )
  1929. {
  1930. if ( s_bScreenEffectTextureIsUpdated == false && !IsPS3() )
  1931. {
  1932. // FIXME: nX/nY/nWidth/nHeight are used here, but the equivalent parameters are ignored in Generate8BitBloomTexture
  1933. UpdateScreenEffectTexture( 0, nX, nY, nWidth, nHeight, false );
  1934. s_bScreenEffectTextureIsUpdated = true;
  1935. }
  1936. GetCurrentTonemappingSystem()->IssueAndReceiveBucketQueries();
  1937. float flTargetScalar = GetCurrentTonemappingSystem()->ComputeTargetTonemapScalar();
  1938. float flTargetScalarClamped = MAX( flAutoExposureMin, MIN( flAutoExposureMax, flTargetScalar ) );
  1939. flTargetScalarClamped = MAX( 0.001f, flTargetScalarClamped ); // Don't let this go to 0!
  1940. GetCurrentTonemappingSystem()->SetTonemapScale( pRenderContext, flTargetScalarClamped, flAutoExposureMin, flAutoExposureMax );
  1941. if ( mat_show_histogram.GetInt() )
  1942. {
  1943. float flTonemapPercentTarget = mat_force_tonemap_percent_target.GetFloat() >= 0.0f ? mat_force_tonemap_percent_target.GetFloat() : g_flTonemapPercentTarget;
  1944. float flTonemapPercentBrightPixels = mat_force_tonemap_percent_bright_pixels.GetFloat() >= 0.0f ? mat_force_tonemap_percent_bright_pixels.GetFloat() : g_flTonemapPercentBrightPixels;
  1945. bool bDrawTextThisFrame = ( mat_show_histogram.GetInt() == 1 );
  1946. if ( IsGameConsole() )
  1947. {
  1948. static float s_flLastTimeUpdate = 0.0f;
  1949. if ( int( gpGlobals->curtime ) - int( s_flLastTimeUpdate ) >= 2 )
  1950. {
  1951. s_flLastTimeUpdate = gpGlobals->curtime;
  1952. bDrawTextThisFrame = true;
  1953. }
  1954. else
  1955. {
  1956. bDrawTextThisFrame = false;
  1957. }
  1958. }
  1959. if ( bDrawTextThisFrame == true )
  1960. {
  1961. if ( mat_tonemap_algorithm.GetInt() == 0 )
  1962. {
  1963. engine->Con_NPrintf( 25 + ( nY / 10 ), "(Original algorithm) Target Scalar = %4.2f Min/Max( %4.2f, %4.2f ) Current Scalar: %4.2f",
  1964. flTargetScalar, flAutoExposureMin, flAutoExposureMax, GetCurrentTonemappingSystem()->GetCurrentTonemappingScale() );
  1965. }
  1966. else
  1967. {
  1968. if ( IsGameConsole() )
  1969. {
  1970. engine->Con_NPrintf( 25 + ( nY / 10 ), "[mat_show_histogram] Target Scalar = %4.2f Min/Max( %4.2f, %4.2f ) Final Scalar: %4.2f\n",
  1971. GetCurrentTonemappingSystem()->ComputeTargetTonemapScalar( true ), flAutoExposureMin, flAutoExposureMax, GetCurrentTonemappingSystem()->GetCurrentTonemappingScale() );
  1972. }
  1973. else
  1974. {
  1975. engine->Con_NPrintf( 25 + ( nY / 10 ), "%.2f%% of pixels above %d%% target @ %4.2f%% Target Scalar = %4.2f Min/Max( %4.2f, %4.2f ) Final Scalar: %4.2f",
  1976. flTonemapPercentBrightPixels, (int)flTonemapPercentTarget,
  1977. ( GetCurrentTonemappingSystem()->FindLocationOfPercentBrightPixels( flTonemapPercentBrightPixels, flTonemapPercentTarget ) * 100.0f ),
  1978. GetCurrentTonemappingSystem()->ComputeTargetTonemapScalar( true ), flAutoExposureMin, flAutoExposureMax, GetCurrentTonemappingSystem()->GetCurrentTonemappingScale() );
  1979. }
  1980. }
  1981. }
  1982. }
  1983. }
  1984. }
  1985. static void CenterScaleQuadUVs( Vector4D & quadUVs, const Vector2D & uvScale )
  1986. {
  1987. Vector2D uvMid = 0.5f*Vector2D( ( quadUVs.z + quadUVs.x ), ( quadUVs.w + quadUVs.y ) );
  1988. Vector2D uvRange= 0.5f*Vector2D( ( quadUVs.z - quadUVs.x ), ( quadUVs.w - quadUVs.y ) );
  1989. quadUVs.x = uvMid.x - uvScale.x*uvRange.x;
  1990. quadUVs.y = uvMid.y - uvScale.y*uvRange.y;
  1991. quadUVs.z = uvMid.x + uvScale.x*uvRange.x;
  1992. quadUVs.w = uvMid.y + uvScale.y*uvRange.y;
  1993. }
  1994. #ifdef IRONSIGHT
  1995. bool ApplyIronSightScopeEffect( int x, int y, int w, int h, CViewSetup *pViewSetup, bool bPreparationStage )
  1996. {
  1997. //the preparation stage returns true if following steps like rendering the scope stencil shape are necessary.
  1998. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1999. if (pPlayer)
  2000. {
  2001. C_WeaponCSBase *pWeapon = (C_WeaponCSBase *)pPlayer->GetActiveWeapon();
  2002. if (pWeapon)
  2003. {
  2004. if ( pWeapon->GetIronSightController() )
  2005. {
  2006. if ( bPreparationStage )
  2007. {
  2008. return pWeapon->GetIronSightController()->PrepareScopeEffect( x, y, w, h, pViewSetup );
  2009. }
  2010. else
  2011. {
  2012. pWeapon->GetIronSightController()->RenderScopeEffect( x, y, w, h, pViewSetup );
  2013. }
  2014. }
  2015. }
  2016. }
  2017. return false;
  2018. }
  2019. #endif
  2020. static ConVar r_queued_post_processing( "r_queued_post_processing", "0" );
  2021. // How much to dice up the screen during post-processing on 360
  2022. // This has really marginal effects, but 4x1 does seem vaguely better for post-processing
  2023. static ConVar mat_postprocess_x( "mat_postprocess_x", "4" );
  2024. static ConVar mat_postprocess_y( "mat_postprocess_y", "1" );
  2025. static ConVar mat_postprocess_enable( "mat_postprocess_enable", "1", FCVAR_CHEAT );
  2026. bool DoEnginePostProcessing( int x, int y, int w, int h, bool bFlashlightIsOn, bool bPostVGui )
  2027. {
  2028. // don't do this if disabled or in alt-tab
  2029. if ( s_bOverridePostProcessingDisable || w <=0 || h <= 0 )
  2030. {
  2031. return false;
  2032. }
  2033. if ( s_bDumpRenderTargets )
  2034. {
  2035. s_bDumpRenderTargets = false; // Turn off from previous frame
  2036. }
  2037. if ( mat_dump_rts.GetBool() )
  2038. {
  2039. s_bDumpRenderTargets = true; // Dump intermediate render targets this frame
  2040. s_nRTIndex = 0; // Used for numbering the TGA files for easy browsing
  2041. mat_dump_rts.SetValue( 0 ); // We only want to capture one frame, on rising edge of this convar
  2042. }
  2043. CMatRenderContextPtr pRenderContext( materials );
  2044. PIXEVENT( pRenderContext, "DoEnginePostProcessing" );
  2045. if ( r_queued_post_processing.GetInt() )
  2046. {
  2047. ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
  2048. if ( pCallQueue )
  2049. {
  2050. pCallQueue->QueueCall( DoEnginePostProcessing, x, y, w, h, bFlashlightIsOn, bPostVGui );
  2051. return false;
  2052. }
  2053. }
  2054. #if defined( _X360 )
  2055. pRenderContext->PushVertexShaderGPRAllocation( 16 ); //max out pixel shader threads
  2056. #endif
  2057. GetTonemapSettingsFromEnvTonemapController();
  2058. g_bFlashlightIsOn = bFlashlightIsOn;
  2059. // Use the appropriate autoexposure min / max settings.
  2060. // Mapmaker's overrides the convar settings.
  2061. float flAutoExposureMin;
  2062. float flAutoExposureMax;
  2063. GetExposureRange( &flAutoExposureMin, &flAutoExposureMax );
  2064. if ( mat_debug_bloom.GetInt() == 1 )
  2065. {
  2066. DrawBloomDebugBoxes( pRenderContext, x, y, w, h );
  2067. }
  2068. s_bScreenEffectTextureIsUpdated = false; // Force an update in tone mapping code
  2069. DoTonemapping( pRenderContext, x, y, w, h, flAutoExposureMin, flAutoExposureMax );
  2070. if ( mat_postprocess_enable.GetInt() == 0 )
  2071. {
  2072. GetCurrentTonemappingSystem()->DisplayHistogram();
  2073. #if defined( _X360 )
  2074. pRenderContext->PopVertexShaderGPRAllocation();
  2075. #endif
  2076. return false;
  2077. }
  2078. ConVarRef mat_software_aa_strength( "mat_software_aa_strength" );
  2079. // Set software-AA on by default for 360
  2080. if ( mat_software_aa_strength.GetFloat() == -1.0f )
  2081. {
  2082. if ( IsGameConsole() )
  2083. {
  2084. mat_software_aa_strength.SetValue( 1.0f );
  2085. if ( g_pMaterialSystem->GetCurrentConfigForVideoCard().m_VideoMode.m_Height > 480 )
  2086. {
  2087. mat_software_aa_quality.SetValue( 0 );
  2088. }
  2089. else
  2090. {
  2091. // For standard-def, we have fewer pixels so we can afford 'high quality' mode (5->9 taps/pixel)
  2092. mat_software_aa_quality.SetValue( 1 );
  2093. // Disable in 480p for now
  2094. mat_software_aa_strength.SetValue( 0.0f );
  2095. }
  2096. }
  2097. else
  2098. {
  2099. mat_software_aa_strength.SetValue( 0.0f );
  2100. }
  2101. }
  2102. // Same trick for setting up the vgui aa strength
  2103. if ( mat_software_aa_strength_vgui.GetFloat() == -1.0f )
  2104. {
  2105. if ( IsGameConsole() && (g_pMaterialSystem->GetCurrentConfigForVideoCard().m_VideoMode.m_Height == 720) )
  2106. {
  2107. mat_software_aa_strength_vgui.SetValue( 2.0f );
  2108. }
  2109. else
  2110. {
  2111. mat_software_aa_strength_vgui.SetValue( 1.0f );
  2112. }
  2113. }
  2114. float flAAStrength;
  2115. // We do a second AA blur pass over the TF intro menus. use mat_software_aa_strength_vgui there instead
  2116. if ( IsGameConsole() && bPostVGui )
  2117. {
  2118. flAAStrength = mat_software_aa_strength_vgui.GetFloat();
  2119. }
  2120. else
  2121. {
  2122. flAAStrength = mat_software_aa_strength.GetFloat();
  2123. }
  2124. // Bloom, software-AA and color-correction (applied in 1 pass, after generation of the bloom texture)
  2125. float flBloomScale = GetBloomAmount();
  2126. bool bPerformSoftwareAA = ( flAAStrength != 0.0f );
  2127. bool bPerformBloom = !bPostVGui && ( flBloomScale > 0.0f );
  2128. bool bPerformColCorrect = !bPostVGui &&
  2129. g_pColorCorrectionMgr->HasNonZeroColorCorrectionWeights() &&
  2130. mat_colorcorrection.GetInt();
  2131. pRenderContext->EnableColorCorrection( bPerformColCorrect );
  2132. bool bPerformLocalContrastEnhancement = false;
  2133. IMaterial* pPostMat;
  2134. if ( engine->IsSplitScreenActive() )
  2135. pPostMat = materials->FindMaterial( "dev/engine_post_splitscreen", TEXTURE_GROUP_OTHER, true );
  2136. else
  2137. {
  2138. #if defined(_PS3)
  2139. if( mat_PS3_findpostvarsfast.GetInt() )
  2140. pPostMat = CEnginePostMaterialProxy::GetEnginePostMaterial( materials );
  2141. else
  2142. pPostMat = materials->FindMaterial( "dev/engine_post", TEXTURE_GROUP_OTHER, true );
  2143. #else
  2144. pPostMat = materials->FindMaterial( "dev/engine_post", TEXTURE_GROUP_OTHER, true );
  2145. #endif
  2146. }
  2147. if ( pPostMat )
  2148. {
  2149. #if defined(_PS3)
  2150. if( mat_PS3_findpostvarsfast.GetInt() )
  2151. {
  2152. bPerformLocalContrastEnhancement = CEnginePostMaterialProxy::GetLocalContrastEnable( materials ) && mat_local_contrast_enable.GetBool();
  2153. }
  2154. else
  2155. {
  2156. IMaterialVar* pMatVar = pPostMat->FindVar( "$localcontrastenable", NULL, false );
  2157. if ( pMatVar )
  2158. {
  2159. bPerformLocalContrastEnhancement = pMatVar->GetIntValue() && mat_local_contrast_enable.GetBool();
  2160. }
  2161. }
  2162. #else
  2163. IMaterialVar* pMatVar = pPostMat->FindVar( "$localcontrastenable", NULL, false );
  2164. if ( pMatVar )
  2165. {
  2166. bPerformLocalContrastEnhancement = pMatVar->GetIntValue() && mat_local_contrast_enable.GetBool();
  2167. }
  2168. #endif
  2169. }
  2170. bool bPerformedPostProcessPass = false;
  2171. if ( true )
  2172. {
  2173. ITexture *pSrc;
  2174. #if defined(_PS3)
  2175. if( mat_PS3_findpostvarsfast.GetInt() )
  2176. pSrc = CEnginePostMaterialProxy::GetSrcTexture( materials );
  2177. else
  2178. #endif
  2179. pSrc = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  2180. int nSrcWidth = pSrc->GetActualWidth();
  2181. int nSrcHeight = pSrc->GetActualHeight();
  2182. ITexture *dest_rt1;
  2183. #if defined(_PS3)
  2184. if( mat_PS3_findpostvarsfast.GetInt() )
  2185. dest_rt1 = CEnginePostMaterialProxy::GetDstRT1Texture( materials );
  2186. else
  2187. #endif
  2188. dest_rt1 = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  2189. if ( !s_bScreenEffectTextureIsUpdated && !IsPS3() )
  2190. {
  2191. UpdateScreenEffectTexture( 0, x, y, w, h, false );
  2192. s_bScreenEffectTextureIsUpdated = true;
  2193. }
  2194. if ( s_bDumpRenderTargets )
  2195. {
  2196. DumpTGAofRenderTarget( nSrcWidth, nSrcHeight, "FullFrameFB" );
  2197. }
  2198. if ( bPerformBloom || bPerformLocalContrastEnhancement )
  2199. {
  2200. Generate8BitBloomTexture( pRenderContext, x, y, w, h, true, false );
  2201. }
  2202. #ifdef PORTAL2
  2203. // Note: the C_Portal_Player::RenderScreenSpaceEffect() call must stay right after
  2204. // Generate8BitBloomTexture(), because on the 360 it relies on the contents of the low-res blur buffer
  2205. // staying in EDRAM unaltered between the two calls. (Screenspace paint uses RGB channels, local contrast
  2206. // uses A of the low-res render target). Or at least this is roughly what the comment said for L4D when I
  2207. // acquired the Boomer vomit particle system by way of my actions.
  2208. // -Ted
  2209. C_Portal_Player::RenderLocalScreenSpaceEffect( PAINT_SCREEN_SPACE_EFFECT, pRenderContext, x, y, w, h );
  2210. #else if CSTRIKE15
  2211. C_CSPlayer::RenderLocalScreenSpaceEffect( AR_LEADER_SCREEN_SPACE_EFFECT, pRenderContext, x, y, w, h );
  2212. #endif
  2213. // Now add bloom (dest_rt0) to the framebuffer and perform software anti-aliasing and
  2214. // colour correction, all in one pass (improves performance, reduces quantization errors)
  2215. //
  2216. // First, set up texel coords (in the bloom and fb textures) at the centres of the outer pixel of the viewport:
  2217. float flFbWidth = ( float )pSrc->GetActualWidth();
  2218. float flFbHeight = ( float )pSrc->GetActualHeight();
  2219. Vector4D fullViewportPostSrcCorners( 0.0f, -0.5f, nSrcWidth/4-1, nSrcHeight/4-1 );
  2220. Vector4D fullViewportPostSrcRect( nSrcWidth * ( ( x + 0 ) / flFbWidth ) / 4.0f + 0.0f, nSrcHeight * ( ( y + 0 ) / flFbHeight ) / 4.0f - 0.5f,
  2221. nSrcWidth * ( ( x + w ) / flFbWidth ) / 4.0f - 1.0f, nSrcHeight * ( ( y + h ) / flFbHeight ) / 4.0f - 1.0f );
  2222. Vector4D fullViewportPostDestCorners( 0.0f, 0.0f, nSrcWidth - 1, nSrcHeight - 1 );
  2223. Rect_t fullViewportPostDestRect = { x, y, w, h };
  2224. Vector2D destTexSize( nSrcWidth, nSrcHeight );
  2225. // When the viewport is not fullscreen, the UV-space size of a pixel changes
  2226. // (due to a stretchrect blit being used in UpdateScreenEffectTexture()), so
  2227. // we need to adjust the corner-pixel UVs sent to our drawrect call:
  2228. Vector2D uvScale( ( nSrcWidth - ( nSrcWidth / (float)w ) ) / ( nSrcWidth - 1 ),
  2229. ( nSrcHeight - ( nSrcHeight / (float)h ) ) / ( nSrcHeight - 1 ) );
  2230. CenterScaleQuadUVs( fullViewportPostSrcCorners, uvScale );
  2231. CenterScaleQuadUVs( fullViewportPostDestCorners, uvScale );
  2232. Rect_t partialViewportPostDestRect = fullViewportPostDestRect;
  2233. Vector4D partialViewportPostSrcCorners = fullViewportPostSrcCorners;
  2234. if ( debug_postproc.GetInt() == 2 )
  2235. {
  2236. // Restrict the post effects to the centre quarter of the screen
  2237. // (we only use a portion of the bloom texture, so this *does* affect bloom texture UVs)
  2238. partialViewportPostDestRect.x += 0.25f*fullViewportPostDestRect.width;
  2239. partialViewportPostDestRect.y += 0.25f*fullViewportPostDestRect.height;
  2240. partialViewportPostDestRect.width -= 0.50f*fullViewportPostDestRect.width;
  2241. partialViewportPostDestRect.height -= 0.50f*fullViewportPostDestRect.height;
  2242. // This math interprets texel coords as being at corner pixel centers (*not* at corner vertices):
  2243. Vector2D uvScale( 1.0f - ( (w / 2) / (float)(w - 1) ),
  2244. 1.0f - ( (h / 2) / (float)(h - 1) ) );
  2245. CenterScaleQuadUVs( partialViewportPostSrcCorners, uvScale );
  2246. }
  2247. // Temporary hack... Color correction was crashing on the first frame
  2248. // when run outside the debugger for some mods (DoD). This forces it to skip
  2249. // a frame, ensuring we don't get the weird texture crash we otherwise would.
  2250. // FIXME: This will be removed when the true cause is found [added: Main CL 144694]
  2251. static bool bFirstFrame = !IsGameConsole();
  2252. if ( !bFirstFrame || !bPerformColCorrect )
  2253. {
  2254. HDRType_t hdrType = g_pMaterialSystemHardwareConfig->GetHDRType();
  2255. if ( hdrType == HDR_TYPE_FLOAT )
  2256. {
  2257. // reset to render the final combine passes to the "real" display backbuffer
  2258. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_BACK_BUFFER_INDEX, BACK_BUFFER_INDEX_DEFAULT );
  2259. pRenderContext->SetRenderTarget( NULL );
  2260. }
  2261. Vector4D v4dFullViewportPostDestRect( fullViewportPostDestRect.x, fullViewportPostDestRect.y,
  2262. fullViewportPostDestRect.x + fullViewportPostDestRect.width - 1,
  2263. fullViewportPostDestRect.y + fullViewportPostDestRect.height - 1 );
  2264. CEnginePostMaterialProxy::SetupEnginePostMaterial( fullViewportPostSrcRect, v4dFullViewportPostDestRect, destTexSize, bPerformSoftwareAA, bPerformBloom, bPerformColCorrect, flAAStrength, flBloomScale );
  2265. pRenderContext->DrawScreenSpaceRectangle( pPostMat,
  2266. 0, 0,
  2267. partialViewportPostDestRect.width, partialViewportPostDestRect.height,
  2268. fullViewportPostSrcRect.x, fullViewportPostSrcRect.y,
  2269. fullViewportPostSrcRect.z, fullViewportPostSrcRect.w,
  2270. dest_rt1->GetActualWidth(), dest_rt1->GetActualHeight(),
  2271. GetClientWorldEntity()->GetClientRenderable(),
  2272. mat_postprocess_x.GetInt(), mat_postprocess_y.GetInt() );
  2273. bPerformedPostProcessPass = true;
  2274. if ( s_bDumpRenderTargets )
  2275. {
  2276. DumpTGAofRenderTarget( partialViewportPostDestRect.width, partialViewportPostDestRect.height, "EnginePost" );
  2277. }
  2278. }
  2279. bFirstFrame = false;
  2280. }
  2281. GetCurrentTonemappingSystem()->DisplayHistogram();
  2282. #if defined( _X360 )
  2283. pRenderContext->PopVertexShaderGPRAllocation();
  2284. #endif
  2285. return bPerformedPostProcessPass;
  2286. }
  2287. void DoBlurFade( float flStrength, float flDesaturate, int x, int y, int w, int h )
  2288. {
  2289. if ( flStrength < 0.0001f )
  2290. {
  2291. return;
  2292. }
  2293. UpdateScreenEffectTexture();
  2294. CMatRenderContextPtr pRenderContext( materials );
  2295. Generate8BitBloomTexture( pRenderContext, x, y, w, h, false, false );
  2296. int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
  2297. pRenderContext->GetViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
  2298. int nRtWidth, nRtHeight;
  2299. pRenderContext->GetRenderTargetDimensions( nRtWidth, nRtHeight );
  2300. IMaterial* pMat = materials->FindMaterial( "dev/fade_blur", TEXTURE_GROUP_OTHER, true );
  2301. bool bFound = false;
  2302. IMaterialVar* pVar = pMat->FindVar( "$c0_x", &bFound );
  2303. if ( pVar && bFound )
  2304. {
  2305. pVar->SetFloatValue( flStrength );
  2306. }
  2307. // Desaturate strength
  2308. pVar = pMat->FindVar( "$c1_x", &bFound );
  2309. if ( pVar && bFound )
  2310. {
  2311. pVar->SetFloatValue( flDesaturate );
  2312. }
  2313. // Color fade
  2314. pVar = pMat->FindVar( "$c2_x", &bFound );
  2315. if ( pVar && bFound )
  2316. {
  2317. pVar->SetFloatValue( mat_blur_r.GetFloat() );
  2318. }
  2319. pVar = pMat->FindVar( "$c2_y", &bFound );
  2320. if ( pVar && bFound )
  2321. {
  2322. pVar->SetFloatValue( mat_blur_g.GetFloat() );
  2323. }
  2324. pVar = pMat->FindVar( "$c2_z", &bFound );
  2325. if ( pVar && bFound )
  2326. {
  2327. pVar->SetFloatValue( mat_blur_b.GetFloat() );
  2328. }
  2329. // Draw
  2330. pRenderContext->DrawScreenSpaceRectangle( pMat, 0, 0, nViewportWidth, nViewportHeight,
  2331. nViewportX, nViewportY,
  2332. nViewportX + nViewportWidth - 1, nViewportY + nViewportHeight - 1,
  2333. nRtWidth, nRtHeight );
  2334. if ( s_bDumpRenderTargets )
  2335. {
  2336. DumpTGAofRenderTarget( nViewportWidth, nViewportHeight, "BlurFade" );
  2337. }
  2338. }
  2339. // Motion Blur Material Proxy =========================================================================================
  2340. static float g_vMotionBlurValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  2341. static float g_vMotionBlurViewportValues[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
  2342. class CMotionBlurMaterialProxy : public CEntityMaterialProxy
  2343. {
  2344. public:
  2345. CMotionBlurMaterialProxy();
  2346. virtual ~CMotionBlurMaterialProxy();
  2347. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  2348. virtual void OnBind( C_BaseEntity *pEntity );
  2349. virtual IMaterial *GetMaterial();
  2350. #if defined(_PS3)
  2351. static IMaterial *GetMotionBlurMaterial( IMaterialSystem * materials );
  2352. #endif
  2353. private:
  2354. IMaterialVar *m_pMaterialParam;
  2355. IMaterialVar *m_pMaterialParamViewport;
  2356. #if defined(_PS3)
  2357. static IMaterial *s_pMotionBlurMaterial;
  2358. #endif
  2359. };
  2360. #if defined(_PS3)
  2361. IMaterial *CMotionBlurMaterialProxy::s_pMotionBlurMaterial = NULL;
  2362. #endif
  2363. CMotionBlurMaterialProxy::CMotionBlurMaterialProxy()
  2364. {
  2365. m_pMaterialParam = NULL;
  2366. #if defined(_PS3)
  2367. s_pMotionBlurMaterial = NULL;
  2368. #endif
  2369. }
  2370. CMotionBlurMaterialProxy::~CMotionBlurMaterialProxy()
  2371. {
  2372. // Do nothing
  2373. }
  2374. bool CMotionBlurMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  2375. {
  2376. bool bFoundVar = false;
  2377. m_pMaterialParam = pMaterial->FindVar( "$MotionBlurInternal", &bFoundVar, false );
  2378. if ( bFoundVar == false)
  2379. return false;
  2380. m_pMaterialParamViewport = pMaterial->FindVar( "$MotionBlurViewportInternal", &bFoundVar, false );
  2381. if ( bFoundVar == false)
  2382. return false;
  2383. return true;
  2384. }
  2385. void CMotionBlurMaterialProxy::OnBind( C_BaseEntity *pEnt )
  2386. {
  2387. if ( m_pMaterialParam != NULL )
  2388. {
  2389. m_pMaterialParam->SetVecValue( g_vMotionBlurValues, 4 );
  2390. }
  2391. if ( m_pMaterialParamViewport != NULL )
  2392. {
  2393. m_pMaterialParamViewport->SetVecValue( g_vMotionBlurViewportValues, 4 );
  2394. }
  2395. }
  2396. IMaterial *CMotionBlurMaterialProxy::GetMaterial()
  2397. {
  2398. if ( m_pMaterialParam == NULL)
  2399. return NULL;
  2400. return m_pMaterialParam->GetOwningMaterial();
  2401. }
  2402. #if defined(_PS3)
  2403. IMaterial *CMotionBlurMaterialProxy::GetMotionBlurMaterial( IMaterialSystem * materials )
  2404. {
  2405. if( s_pMotionBlurMaterial == NULL)
  2406. {
  2407. s_pMotionBlurMaterial = materials->FindMaterial( "dev/motion_blur", TEXTURE_GROUP_OTHER, true );
  2408. }
  2409. return s_pMotionBlurMaterial;
  2410. }
  2411. #endif
  2412. EXPOSE_MATERIAL_PROXY( CMotionBlurMaterialProxy, MotionBlur );
  2413. //=====================================================================================================================
  2414. // Image-space Motion Blur ============================================================================================
  2415. //=====================================================================================================================
  2416. #ifdef PORTAL2
  2417. ConVar mat_motion_blur_forward_enabled( "mat_motion_blur_forward_enabled", "1" );
  2418. ConVar mat_motion_blur_falling_min( "mat_motion_blur_falling_min", "8.0" );
  2419. #else
  2420. ConVar mat_motion_blur_forward_enabled( "mat_motion_blur_forward_enabled", "0" );
  2421. ConVar mat_motion_blur_falling_min( "mat_motion_blur_falling_min", "10.0" );
  2422. #endif
  2423. ConVar mat_motion_blur_falling_max( "mat_motion_blur_falling_max", "20.0" );
  2424. ConVar mat_motion_blur_falling_intensity( "mat_motion_blur_falling_intensity", "1.0" );
  2425. //ConVar mat_motion_blur_roll_intensity( "mat_motion_blur_roll_intensity", "1.0" );
  2426. ConVar mat_motion_blur_rotation_intensity( "mat_motion_blur_rotation_intensity", "1.0" );
  2427. ConVar mat_motion_blur_strength( "mat_motion_blur_strength", "1.0" );
  2428. struct MotionBlurHistory_t
  2429. {
  2430. MotionBlurHistory_t()
  2431. {
  2432. m_flLastTimeUpdate = 0.0f;
  2433. m_flPreviousPitch = 0.0f;
  2434. m_flPreviousYaw = 0.0f;
  2435. m_vPreviousPositon.Init( 0.0f, 0.0f, 0.0f );
  2436. m_mPreviousFrameBasisVectors;
  2437. m_flNoRotationalMotionBlurUntil = 0.0f;
  2438. SetIdentityMatrix( m_mPreviousFrameBasisVectors );
  2439. }
  2440. float m_flLastTimeUpdate;
  2441. float m_flPreviousPitch;
  2442. float m_flPreviousYaw;
  2443. Vector m_vPreviousPositon;
  2444. matrix3x4_t m_mPreviousFrameBasisVectors;
  2445. float m_flNoRotationalMotionBlurUntil;
  2446. };
  2447. bool DoImageSpaceMotionBlur( const CViewSetup &view )
  2448. {
  2449. #ifdef PORTAL2
  2450. // DEMO HACKS!!!
  2451. if( gpGlobals->maxClients == 2 )
  2452. return false;
  2453. #endif
  2454. ConVarRef mat_motion_blur_enabled( "mat_motion_blur_enabled" );
  2455. if ( ( !mat_motion_blur_enabled.GetInt() ) || ( view.m_nMotionBlurMode == MOTION_BLUR_DISABLE ) )
  2456. {
  2457. return false;
  2458. }
  2459. int x = view.x;
  2460. int y = view.y;
  2461. int w = view.width;
  2462. int h = view.height;
  2463. bool bSFMBlur = ( view.m_nMotionBlurMode == MOTION_BLUR_SFM );
  2464. //======================================================================================================//
  2465. // Get these convars here to make it easier to remove them later and to default each client differently //
  2466. //======================================================================================================//
  2467. float flMotionBlurRotationIntensity = mat_motion_blur_rotation_intensity.GetFloat() * 0.15f; // The default is to not blur past 15% of the range
  2468. float flMotionBlurRollIntensity = 0.3f; // * mat_motion_blur_roll_intensity.GetFloat(); // The default is to not blur past 30% of the range
  2469. float flMotionBlurFallingIntensity = mat_motion_blur_falling_intensity.GetFloat();
  2470. float flMotionBlurFallingMin = mat_motion_blur_falling_min.GetFloat();
  2471. float flMotionBlurFallingMax = mat_motion_blur_falling_max.GetFloat();
  2472. float flMotionBlurGlobalStrength = mat_motion_blur_strength.GetFloat();
  2473. //===============================================================================//
  2474. // Set global g_vMotionBlurValues[4] values so material proxy can get the values //
  2475. //===============================================================================//
  2476. if ( true )
  2477. {
  2478. //=====================//
  2479. // Previous frame data //
  2480. //=====================//
  2481. static MotionBlurHistory_t s_History[ MAX_SPLITSCREEN_PLAYERS ];
  2482. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  2483. MotionBlurHistory_t &history = s_History[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  2484. //float vPreviousSideVec[3] = { s_mPreviousFrameBasisVectors[0][1], s_mPreviousFrameBasisVectors[1][1], s_mPreviousFrameBasisVectors[2][1] };
  2485. //float vPreviousForwardVec[3] = { s_mPreviousFrameBasisVectors[0][0], s_mPreviousFrameBasisVectors[1][0], s_mPreviousFrameBasisVectors[2][0] };
  2486. //float vPreviousUpVec[3] = { s_mPreviousFrameBasisVectors[0][2], s_mPreviousFrameBasisVectors[1][2], s_mPreviousFrameBasisVectors[2][2] };
  2487. float flTimeElapsed;
  2488. // Motion blur driven by CViewSetup, not engine time (currently only driven by SFM)
  2489. if ( bSFMBlur )
  2490. {
  2491. history.m_flLastTimeUpdate = 0.0f; // Don't care about these, but zero them out
  2492. history.m_flNoRotationalMotionBlurUntil = 0.0f; //
  2493. flTimeElapsed = view.m_flShutterTime;
  2494. history.m_vPreviousPositon[0] = view.m_vShutterOpenPosition.x; //
  2495. history.m_vPreviousPositon[1] = view.m_vShutterOpenPosition.y; // Slam "previous" values to shutter open values
  2496. history.m_vPreviousPositon[2] = view.m_vShutterOpenPosition.z; //
  2497. AngleMatrix( view.m_shutterOpenAngles, history.m_mPreviousFrameBasisVectors );//
  2498. history.m_flPreviousPitch = view.m_shutterOpenAngles[PITCH]; // Get "previous" pitch & wrap to +-180
  2499. while ( history.m_flPreviousPitch > 180.0f )
  2500. history.m_flPreviousPitch -= 360.0f;
  2501. while ( history.m_flPreviousPitch < -180.0f )
  2502. history.m_flPreviousPitch += 360.0f;
  2503. history.m_flPreviousYaw = view.m_shutterOpenAngles[YAW]; // Get "previous" yaw & wrap to +-180
  2504. while ( history.m_flPreviousYaw > 180.0f )
  2505. history.m_flPreviousYaw -= 360.0f;
  2506. while ( history.m_flPreviousYaw < -180.0f )
  2507. history.m_flPreviousYaw += 360.0f;
  2508. }
  2509. else // view.m_nDoMotionBlurMode == MOTION_BLUR_GAME
  2510. {
  2511. flTimeElapsed = gpGlobals->realtime - history.m_flLastTimeUpdate;
  2512. }
  2513. #ifdef PORTAL2
  2514. float flCurrentPitch = view.angles[PITCH];
  2515. float flCurrentYaw = view.angles[YAW];
  2516. CPortal_Player *pPortalPlayer = ToPortalPlayer( C_BasePlayer::GetLocalPlayer() );
  2517. if ( pPortalPlayer )
  2518. {
  2519. Vector vUp = pPortalPlayer->GetPortalPlayerLocalData().m_Up;
  2520. // compute flCurrentPitch by getting angle between forward vector and up vector
  2521. matrix3x4_t mCurrentBasisVectors;
  2522. AngleMatrix( view.angles, mCurrentBasisVectors );
  2523. Vector vCurrentForward( mCurrentBasisVectors[0][0], mCurrentBasisVectors[1][0], mCurrentBasisVectors[2][0] );
  2524. Vector vCurrentRight( mCurrentBasisVectors[0][1], mCurrentBasisVectors[1][1], mCurrentBasisVectors[2][1] );
  2525. AngleVectors( view.angles, &vCurrentForward );
  2526. flCurrentPitch = RAD2DEG( acosf( DotProduct( vUp, vCurrentForward ) ) ) - 90.f;
  2527. // compute flCurrentYaw by accumulating the offset
  2528. Vector vOldRight( history.m_mPreviousFrameBasisVectors[0][1], history.m_mPreviousFrameBasisVectors[1][1], history.m_mPreviousFrameBasisVectors[2][1] );
  2529. float flDot = DotProduct( vCurrentRight, vOldRight );
  2530. flDot = clamp( flDot, -1.f, 1.f );
  2531. if ( vCurrentRight == vOldRight )
  2532. flDot = 1.f;
  2533. float flAcos = acosf( flDot );
  2534. Vector vCross = CrossProduct( vCurrentRight, vOldRight );
  2535. float flSign = -clamp( DotProduct( vCross, vUp ), -1.f, 1.f );
  2536. float flYawOffset = Sign( flSign ) * RAD2DEG( flAcos );
  2537. flCurrentYaw = history.m_flPreviousYaw + flYawOffset;
  2538. }
  2539. // wrap pitch and yaw to +-180
  2540. while ( flCurrentPitch > 180.0f )
  2541. flCurrentPitch -= 360.0f;
  2542. while ( flCurrentPitch < -180.0f )
  2543. flCurrentPitch += 360.0f;
  2544. while ( flCurrentYaw > 180.0f )
  2545. flCurrentYaw -= 360.0f;
  2546. while ( flCurrentYaw < -180.0f )
  2547. flCurrentYaw += 360.0f;
  2548. #else
  2549. //===================================//
  2550. // Get current pitch & wrap to +-180 //
  2551. //===================================//
  2552. float flCurrentPitch = view.angles[PITCH];
  2553. if ( bSFMBlur )
  2554. flCurrentPitch = view.m_shutterCloseAngles[PITCH];
  2555. while ( flCurrentPitch > 180.0f )
  2556. flCurrentPitch -= 360.0f;
  2557. while ( flCurrentPitch < -180.0f )
  2558. flCurrentPitch += 360.0f;
  2559. //=================================//
  2560. // Get current yaw & wrap to +-180 //
  2561. //=================================//
  2562. float flCurrentYaw = view.angles[YAW];
  2563. if ( bSFMBlur )
  2564. flCurrentYaw = view.m_shutterCloseAngles[YAW];
  2565. while ( flCurrentYaw > 180.0f )
  2566. flCurrentYaw -= 360.0f;
  2567. while ( flCurrentYaw < -180.0f )
  2568. flCurrentYaw += 360.0f;
  2569. #endif
  2570. /*engine->Con_NPrintf( 0, "Blur Pitch: %6.2f Yaw: %6.2f", flCurrentPitch, flCurrentYaw );
  2571. engine->Con_NPrintf( 1, "Blur FOV: %6.2f Aspect: %6.2f Ortho: %s", view.fov, view.m_flAspectRatio, view.m_bOrtho ? "Yes" : "No" );
  2572. engine->Con_NPrintf( 2, "View Angles: %6.2f %6.2f %6.2f", XYZ(view.angles) );*/
  2573. //===========================//
  2574. // Get current basis vectors //
  2575. //===========================//
  2576. matrix3x4_t mCurrentBasisVectors;
  2577. if ( bSFMBlur )
  2578. {
  2579. AngleMatrix( view.m_shutterCloseAngles, mCurrentBasisVectors );
  2580. }
  2581. else
  2582. {
  2583. AngleMatrix( view.angles, mCurrentBasisVectors );
  2584. }
  2585. Vector vCurrentSideVec( mCurrentBasisVectors[0][1], mCurrentBasisVectors[1][1], mCurrentBasisVectors[2][1] );
  2586. Vector vCurrentForwardVec( mCurrentBasisVectors[0][0], mCurrentBasisVectors[1][0], mCurrentBasisVectors[2][0] );
  2587. //Vector vCurrentUpVec( mCurrentBasisVectors[0][2], mCurrentBasisVectors[1][2], mCurrentBasisVectors[2][2] );
  2588. //===========================================================================//
  2589. // Get current position (shutter close time when SFM is driving motion blur) //
  2590. //===========================================================================//
  2591. Vector vCurrentPosition = view.origin;
  2592. if ( bSFMBlur )
  2593. {
  2594. vCurrentPosition[0] = view.m_vShutterClosePosition.x;
  2595. vCurrentPosition[1] = view.m_vShutterClosePosition.y;
  2596. vCurrentPosition[2] = view.m_vShutterClosePosition.z;
  2597. }
  2598. //===============================================================//
  2599. // Evaluate change in position to determine if we need to update //
  2600. //===============================================================//
  2601. Vector vPositionChange( 0.0f, 0.0f, 0.0f );
  2602. VectorSubtract( history.m_vPreviousPositon, vCurrentPosition, vPositionChange );
  2603. if ( ( VectorLength( vPositionChange ) > 30.0f ) && ( flTimeElapsed >= 0.5f ) && !bSFMBlur )
  2604. {
  2605. //=======================================================//
  2606. // If we moved a far distance in one frame and more than //
  2607. // half a second elapsed, disable motion blur this frame //
  2608. //=======================================================//
  2609. //engine->Con_NPrintf( 8, " Pos change && time > 0.5 seconds %f ", gpGlobals->realtime );
  2610. g_vMotionBlurValues[0] = 0.0f;
  2611. g_vMotionBlurValues[1] = 0.0f;
  2612. g_vMotionBlurValues[2] = 0.0f;
  2613. g_vMotionBlurValues[3] = 0.0f;
  2614. }
  2615. else if ( ( flTimeElapsed > ( 1.0f / 15.0f ) ) && !bSFMBlur )
  2616. {
  2617. //==========================================//
  2618. // If slower than 15 fps, don't motion blur //
  2619. //==========================================//
  2620. g_vMotionBlurValues[0] = 0.0f;
  2621. g_vMotionBlurValues[1] = 0.0f;
  2622. g_vMotionBlurValues[2] = 0.0f;
  2623. g_vMotionBlurValues[3] = 0.0f;
  2624. }
  2625. else if ( ( VectorLength( vPositionChange ) > 50.0f ) && !bSFMBlur )
  2626. {
  2627. //================================================================================//
  2628. // We moved a far distance in a frame, use the same motion blur as last frame //
  2629. // because I think we just went through a portal (should we ifdef this behavior?) //
  2630. //================================================================================//
  2631. //engine->Con_NPrintf( 8, " Position changed %f units @ %.2f time ", VectorLength( vPositionChange ), gpGlobals->realtime );
  2632. history.m_flNoRotationalMotionBlurUntil = gpGlobals->realtime + 1.0f; // Wait a second until the portal craziness calms down
  2633. }
  2634. else
  2635. {
  2636. //====================//
  2637. // Normal update path //
  2638. //====================//
  2639. // Compute horizontal and vertical fov
  2640. float flHorizontalFov = view.fov;
  2641. float flVerticalFov = ( view.m_flAspectRatio <= 0.0f ) ? ( view.fov ) : ( view.fov / view.m_flAspectRatio );
  2642. //engine->Con_NPrintf( 2, "Horizontal Fov: %6.2f Vertical Fov: %6.2f", flHorizontalFov, flVerticalFov );
  2643. //=====================//
  2644. // Forward motion blur //
  2645. //=====================//
  2646. float flViewDotMotion = DotProduct( vCurrentForwardVec, vPositionChange );
  2647. if ( mat_motion_blur_forward_enabled.GetBool() ) // Want forward and falling
  2648. g_vMotionBlurValues[2] = flViewDotMotion;
  2649. else // Falling only
  2650. g_vMotionBlurValues[2] = flViewDotMotion * fabs( vCurrentForwardVec[2] ); // Only want this if we're looking up or down;
  2651. //====================================//
  2652. // Yaw (Compensate for circle strafe) //
  2653. //====================================//
  2654. float flSideDotMotion = DotProduct( vCurrentSideVec, vPositionChange );
  2655. float flYawDiffOriginal = history.m_flPreviousYaw - flCurrentYaw;
  2656. if ( ( ( history.m_flPreviousYaw - flCurrentYaw > 180.0f ) || ( history.m_flPreviousYaw - flCurrentYaw < -180.0f ) ) &&
  2657. ( ( history.m_flPreviousYaw + flCurrentYaw > -180.0f ) && ( history.m_flPreviousYaw + flCurrentYaw < 180.0f ) ) )
  2658. flYawDiffOriginal = history.m_flPreviousYaw + flCurrentYaw;
  2659. float flYawDiffAdjusted = flYawDiffOriginal + ( flSideDotMotion / 3.0f ); // Yes, 3.0 is a magic number, sue me
  2660. // Make sure the adjustment only lessens the effect, not magnify it or reverse it
  2661. if ( flYawDiffOriginal < 0.0f )
  2662. flYawDiffAdjusted = clamp ( flYawDiffAdjusted, flYawDiffOriginal, 0.0f );
  2663. else
  2664. flYawDiffAdjusted = clamp ( flYawDiffAdjusted, 0.0f, flYawDiffOriginal );
  2665. // Use pitch to dampen yaw
  2666. float flUndampenedYaw = flYawDiffAdjusted / flHorizontalFov;
  2667. g_vMotionBlurValues[0] = flUndampenedYaw * ( 1.0f - ( fabs( flCurrentPitch ) / 90.0f ) ); // Dampen horizontal yaw blur based on pitch
  2668. //engine->Con_NPrintf( 4, "flSideDotMotion: %6.2f yaw diff: %6.2f ( %6.2f, %6.2f )", flSideDotMotion, ( s_flPreviousYaw - flCurrentYaw ), flYawDiffOriginal, flYawDiffAdjusted );
  2669. //=======================================//
  2670. // Pitch (Compensate for forward motion) //
  2671. //=======================================//
  2672. float flPitchCompensateMask = 1.0f - ( ( 1.0f - fabs( vCurrentForwardVec[2] ) ) * ( 1.0f - fabs( vCurrentForwardVec[2] ) ) );
  2673. float flPitchDiffOriginal = history.m_flPreviousPitch - flCurrentPitch;
  2674. float flPitchDiffAdjusted = flPitchDiffOriginal;
  2675. if ( flCurrentPitch > 0.0f )
  2676. flPitchDiffAdjusted = flPitchDiffOriginal - ( ( flViewDotMotion / 2.0f ) * flPitchCompensateMask ); // Yes, 2.0 is a magic number, sue me
  2677. else
  2678. flPitchDiffAdjusted = flPitchDiffOriginal + ( ( flViewDotMotion / 2.0f ) * flPitchCompensateMask ); // Yes, 2.0 is a magic number, sue me
  2679. // Make sure the adjustment only lessens the effect, not magnify it or reverse it
  2680. if ( flPitchDiffOriginal < 0.0f )
  2681. flPitchDiffAdjusted = clamp ( flPitchDiffAdjusted, flPitchDiffOriginal, 0.0f );
  2682. else
  2683. flPitchDiffAdjusted = clamp ( flPitchDiffAdjusted, 0.0f, flPitchDiffOriginal );
  2684. g_vMotionBlurValues[1] = flPitchDiffAdjusted / flVerticalFov;
  2685. //engine->Con_NPrintf( 5, "flViewDotMotion %6.2f, flPitchCompensateMask %6.2f, flPitchDiffOriginal %6.2f, flPitchDiffAdjusted %6.2f, g_vMotionBlurValues[1] %6.2f", flViewDotMotion, flPitchCompensateMask, flPitchDiffOriginal, flPitchDiffAdjusted, g_vMotionBlurValues[1]);
  2686. //========================================================//
  2687. // Roll (Enabled when we're looking down and yaw changes) //
  2688. //========================================================//
  2689. g_vMotionBlurValues[3] = flUndampenedYaw; // Roll starts out as undampened yaw intensity and is then scaled by pitch
  2690. g_vMotionBlurValues[3] *= ( fabs( flCurrentPitch ) / 90.0f ) * ( fabs( flCurrentPitch ) / 90.0f ) * ( fabs( flCurrentPitch ) / 90.0f ); // Dampen roll based on pitch^3
  2691. //engine->Con_NPrintf( 4, "[2] before scale and bias: %6.2f", g_vMotionBlurValues[2] );
  2692. //engine->Con_NPrintf( 5, "[3] before scale and bias: %6.2f", g_vMotionBlurValues[3] );
  2693. //==============================================================//
  2694. // Time-adjust falling effect until we can do something smarter //
  2695. //==============================================================//
  2696. if ( flTimeElapsed > 0.0f )
  2697. g_vMotionBlurValues[2] /= flTimeElapsed * 30.0f; // 1/30th of a second?
  2698. else
  2699. g_vMotionBlurValues[2] = 0.0f;
  2700. // Scale and bias values after time adjustment
  2701. g_vMotionBlurValues[2] = clamp( ( fabs( g_vMotionBlurValues[2] ) - flMotionBlurFallingMin ) / ( flMotionBlurFallingMax - flMotionBlurFallingMin ), 0.0f, 1.0f ) * ( g_vMotionBlurValues[2] >= 0.0f ? 1.0f : -1.0f );
  2702. g_vMotionBlurValues[2] /= 30.0f; // To counter-adjust for time adjustment above
  2703. //=================//
  2704. // Apply intensity //
  2705. //=================//
  2706. g_vMotionBlurValues[0] *= flMotionBlurRotationIntensity * flMotionBlurGlobalStrength;
  2707. g_vMotionBlurValues[1] *= flMotionBlurRotationIntensity * flMotionBlurGlobalStrength;
  2708. g_vMotionBlurValues[2] *= flMotionBlurFallingIntensity * flMotionBlurGlobalStrength;
  2709. g_vMotionBlurValues[3] *= flMotionBlurRollIntensity * flMotionBlurGlobalStrength;
  2710. //===============================================================//
  2711. // Dampen motion blur from 100%-0% as fps drops from 50fps-30fps //
  2712. //===============================================================//
  2713. if ( !IsGameConsole() && !bSFMBlur ) // I'm not doing this on the 360 yet since I can't test it. SFM doesn't need it either
  2714. {
  2715. float flSlowFps = 30.0f;
  2716. float flFastFps = 50.0f;
  2717. float flCurrentFps = ( flTimeElapsed > 0.0f ) ? ( 1.0f / flTimeElapsed ) : 0.0f;
  2718. float flDampenFactor = clamp( ( ( flCurrentFps - flSlowFps ) / ( flFastFps - flSlowFps ) ), 0.0f, 1.0f );
  2719. //engine->Con_NPrintf( 4, "gpGlobals->realtime %.2f gpGlobals->curtime %.2f", gpGlobals->realtime, gpGlobals->curtime );
  2720. //engine->Con_NPrintf( 5, "flCurrentFps %.2f", flCurrentFps );
  2721. //engine->Con_NPrintf( 7, "flTimeElapsed %.2f", flTimeElapsed );
  2722. g_vMotionBlurValues[0] *= flDampenFactor;
  2723. g_vMotionBlurValues[1] *= flDampenFactor;
  2724. g_vMotionBlurValues[2] *= flDampenFactor;
  2725. g_vMotionBlurValues[3] *= flDampenFactor;
  2726. //engine->Con_NPrintf( 6, "Dampen: %.2f", flDampenFactor );
  2727. }
  2728. //engine->Con_NPrintf( 6, "Final values: { %6.2f%%, %6.2f%%, %6.2f%%, %6.2f%% }", g_vMotionBlurValues[0]*100.0f, g_vMotionBlurValues[1]*100.0f, g_vMotionBlurValues[2]*100.0f, g_vMotionBlurValues[3]*100.0f );
  2729. }
  2730. //============================================//
  2731. // Zero out blur if still in that time window //
  2732. //============================================//
  2733. if ( !bSFMBlur && ( gpGlobals->realtime < history.m_flNoRotationalMotionBlurUntil ) )
  2734. {
  2735. //engine->Con_NPrintf( 9, " No Rotation @ %f ", gpGlobals->realtime );
  2736. // Zero out rotational blur but leave forward/falling blur alone
  2737. g_vMotionBlurValues[0] = 0.0f; // X
  2738. g_vMotionBlurValues[1] = 0.0f; // Y
  2739. g_vMotionBlurValues[3] = 0.0f; // Roll
  2740. }
  2741. else
  2742. {
  2743. history.m_flNoRotationalMotionBlurUntil = 0.0f;
  2744. }
  2745. //================================================================================//
  2746. // Disable roll and forward blur if in split screen and reduce the blur intensity //
  2747. //================================================================================//
  2748. if ( engine->IsSplitScreenActive() )
  2749. {
  2750. g_vMotionBlurValues[0] *= 0.25f; // X
  2751. g_vMotionBlurValues[1] *= 0.25f; // Y
  2752. g_vMotionBlurValues[2] = 0.0f;
  2753. g_vMotionBlurValues[3] = 0.0f;
  2754. }
  2755. //====================================//
  2756. // Store current frame for next frame //
  2757. //====================================//
  2758. VectorCopy( vCurrentPosition, history.m_vPreviousPositon );
  2759. history.m_mPreviousFrameBasisVectors = mCurrentBasisVectors;
  2760. history.m_flPreviousPitch = flCurrentPitch;
  2761. history.m_flPreviousYaw = flCurrentYaw;
  2762. history.m_flLastTimeUpdate = gpGlobals->realtime;
  2763. }
  2764. //engine->Con_NPrintf( 6, "Final values: { %6.2f%%, %6.2f%%, %6.2f%%, %6.2f%% }", g_vMotionBlurValues[0]*100.0f, g_vMotionBlurValues[1]*100.0f, g_vMotionBlurValues[2]*100.0f, g_vMotionBlurValues[3]*100.0f );
  2765. #if defined ( PORTAL2 )
  2766. C_Portal_Player* pLocalPlayer = C_Portal_Player::GetLocalPortalPlayer( GET_ACTIVE_SPLITSCREEN_SLOT() );
  2767. if ( pLocalPlayer && pLocalPlayer->GetMotionBlurAmount() > 0.0f )
  2768. {
  2769. g_vMotionBlurValues[2] = pLocalPlayer->GetMotionBlurAmount();
  2770. }
  2771. #endif
  2772. //==========================================//
  2773. // Set global g_vMotionBlurViewportValues[] //
  2774. //==========================================//
  2775. if ( true )
  2776. {
  2777. ITexture *pSrc;
  2778. #if defined(_PS3)
  2779. if( mat_PS3_findpostvarsfast.GetInt() )
  2780. pSrc = CEnginePostMaterialProxy::GetSrcTexture( materials );
  2781. else
  2782. #endif
  2783. pSrc = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  2784. float flSrcWidth = ( float )pSrc->GetActualWidth();
  2785. float flSrcHeight = ( float )pSrc->GetActualHeight();
  2786. // NOTE #1: float4 stored as ( minx, miny, maxy, maxx )...z&w have been swapped to save pixel shader instructions
  2787. // NOTE #2: This code should definitely work for 2 players (horizontal or vertical), or 4 players (4 corners), but
  2788. // it might have to be modified if we ever want to support other split screen configurations
  2789. int nOffset; // Offset by one pixel to land in the correct half
  2790. // Left
  2791. nOffset = ( x > 0 ) ? 1 : 0;
  2792. g_vMotionBlurViewportValues[0] = ( float )( x + nOffset ) / ( flSrcWidth - 1 );
  2793. // Right
  2794. nOffset = ( x < ( flSrcWidth - 1 ) ) ? -1 : 0;
  2795. g_vMotionBlurViewportValues[3] = ( float )( x + w + nOffset ) / ( flSrcWidth - 1 );
  2796. // Top
  2797. nOffset = ( y > 0 ) ? 1 : 0; // Offset by one pixel to land in the correct half
  2798. g_vMotionBlurViewportValues[1] = ( float )( y + nOffset ) / ( flSrcHeight - 1 );
  2799. // Bottom
  2800. nOffset = ( y < ( flSrcHeight - 1 ) ) ? -1 : 0;
  2801. g_vMotionBlurViewportValues[2] = ( float )( y + h + nOffset ) / ( flSrcHeight - 1 );
  2802. // Only allow clamping to happen in the middle of the screen, so nudge the clamp values out if they're on the border of the screen
  2803. for ( int i = 0; i < 4; i++ )
  2804. {
  2805. if ( g_vMotionBlurViewportValues[i] <= 0.0f )
  2806. g_vMotionBlurViewportValues[i] = -1.0f;
  2807. else if ( g_vMotionBlurViewportValues[i] >= 1.0f )
  2808. g_vMotionBlurViewportValues[i] = 2.0f;
  2809. }
  2810. }
  2811. //=============================================================================================//
  2812. // Render quad and let material proxy pick up the g_vMotionBlurValues[4] values just set above //
  2813. //=============================================================================================//
  2814. bool bPerformedMotionBlur = false;
  2815. if ( true )
  2816. {
  2817. CMatRenderContextPtr pRenderContext( materials );
  2818. ITexture *pSrc;
  2819. #if defined(_PS3)
  2820. if( mat_PS3_findpostvarsfast.GetInt() )
  2821. pSrc = CEnginePostMaterialProxy::GetSrcPS3Texture( materials );
  2822. else
  2823. #endif
  2824. pSrc = materials->FindTexture( IsPS3() ? "^PS3^BACKBUFFER" : "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  2825. int nSrcWidth = pSrc->GetActualWidth();
  2826. int nSrcHeight = pSrc->GetActualHeight();
  2827. int nViewportWidth, nViewportHeight, nDummy;
  2828. pRenderContext->GetViewport( nDummy, nDummy, nViewportWidth, nViewportHeight );
  2829. if ( !IsPS3() )
  2830. {
  2831. UpdateScreenEffectTexture( 0, x, y, w, h, false );
  2832. }
  2833. // Get material pointer
  2834. IMaterial *pMatMotionBlur;
  2835. #if defined(_PS3)
  2836. if( mat_PS3_findpostvarsfast.GetInt() )
  2837. pMatMotionBlur = CMotionBlurMaterialProxy::GetMotionBlurMaterial( materials );
  2838. else
  2839. #endif
  2840. pMatMotionBlur = materials->FindMaterial( "dev/motion_blur", TEXTURE_GROUP_OTHER, true );
  2841. //SetRenderTargetAndViewPort( dest_rt0 );
  2842. //pRenderContext->PopRenderTargetAndViewport();
  2843. if ( pMatMotionBlur != NULL && nSrcWidth > 0 && nSrcHeight > 0 )
  2844. {
  2845. pRenderContext->DrawScreenSpaceRectangle(
  2846. pMatMotionBlur,
  2847. 0, 0, nViewportWidth, nViewportHeight,
  2848. x, y, x + w-1, y + h-1,
  2849. nSrcWidth, nSrcHeight, GetClientWorldEntity()->GetClientRenderable() );
  2850. bPerformedMotionBlur = true;
  2851. if ( s_bDumpRenderTargets )
  2852. {
  2853. DumpTGAofRenderTarget( nViewportWidth, nViewportHeight, "MotionBlur" );
  2854. }
  2855. }
  2856. }
  2857. return bPerformedMotionBlur;
  2858. }
  2859. //=====================================================================================================================
  2860. // Depth of field =====================================================================================================
  2861. //=====================================================================================================================
  2862. ConVar mat_dof_enabled( "mat_dof_enabled", "1" );
  2863. ConVar mat_dof_override( "mat_dof_override", "0" );
  2864. ConVar mat_dof_near_blur_depth( "mat_dof_near_blur_depth", "20.0" );
  2865. ConVar mat_dof_near_focus_depth( "mat_dof_near_focus_depth", "100.0" );
  2866. ConVar mat_dof_far_focus_depth( "mat_dof_far_focus_depth", "250.0" );
  2867. ConVar mat_dof_far_blur_depth( "mat_dof_far_blur_depth", "1000.0" );
  2868. ConVar mat_dof_near_blur_radius( "mat_dof_near_blur_radius", "10.0" );
  2869. ConVar mat_dof_far_blur_radius( "mat_dof_far_blur_radius", "5.0" );
  2870. ConVar mat_dof_quality( "mat_dof_quality", "0" );
  2871. static float GetNearBlurDepth()
  2872. {
  2873. return mat_dof_override.GetBool() ? mat_dof_near_blur_depth.GetFloat() : g_flDOFNearBlurDepth;
  2874. }
  2875. static float GetNearFocusDepth()
  2876. {
  2877. return mat_dof_override.GetBool() ? mat_dof_near_focus_depth.GetFloat() : g_flDOFNearFocusDepth;
  2878. }
  2879. static float GetFarFocusDepth()
  2880. {
  2881. return mat_dof_override.GetBool() ? mat_dof_far_focus_depth.GetFloat() : g_flDOFFarFocusDepth;
  2882. }
  2883. static float GetFarBlurDepth()
  2884. {
  2885. return mat_dof_override.GetBool() ? mat_dof_far_blur_depth.GetFloat() : g_flDOFFarBlurDepth;
  2886. }
  2887. static float GetNearBlurRadius()
  2888. {
  2889. return mat_dof_override.GetBool() ? mat_dof_near_blur_radius.GetFloat() : g_flDOFNearBlurRadius;
  2890. }
  2891. static float GetFarBlurRadius()
  2892. {
  2893. return mat_dof_override.GetBool() ? mat_dof_far_blur_radius.GetFloat() : g_flDOFFarBlurRadius;
  2894. }
  2895. bool IsDepthOfFieldEnabled()
  2896. {
  2897. const CViewSetup *pViewSetup = view->GetViewSetup();
  2898. if ( !pViewSetup )
  2899. return false;
  2900. // We need high-precision depth, which we currently only get in float HDR mode
  2901. if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_FLOAT )
  2902. return false;
  2903. if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 92 )
  2904. return false;
  2905. // Only SFM sets this at the moment...it supersedes mat_dof_ convars if true
  2906. if ( pViewSetup->m_bDoDepthOfField )
  2907. return true;
  2908. if ( !mat_dof_enabled.GetBool() )
  2909. return false;
  2910. if ( mat_dof_override.GetBool() == true )
  2911. {
  2912. return mat_dof_enabled.GetBool();
  2913. }
  2914. else
  2915. {
  2916. return g_bDOFEnabled;
  2917. }
  2918. }
  2919. static inline bool SetMaterialVarFloat( IMaterial* pMat, const char* pVarName, float flValue )
  2920. {
  2921. Assert( pMat != NULL );
  2922. Assert( pVarName != NULL );
  2923. if ( pMat == NULL || pVarName == NULL )
  2924. {
  2925. return false;
  2926. }
  2927. bool bFound = false;
  2928. IMaterialVar* pVar = pMat->FindVar( pVarName, &bFound );
  2929. if ( bFound )
  2930. {
  2931. pVar->SetFloatValue( flValue );
  2932. }
  2933. return bFound;
  2934. }
  2935. static inline bool SetMaterialVarInt( IMaterial* pMat, const char* pVarName, int nValue )
  2936. {
  2937. Assert( pMat != NULL );
  2938. Assert( pVarName != NULL );
  2939. if ( pMat == NULL || pVarName == NULL )
  2940. {
  2941. return false;
  2942. }
  2943. bool bFound = false;
  2944. IMaterialVar* pVar = pMat->FindVar( pVarName, &bFound );
  2945. if ( bFound )
  2946. {
  2947. pVar->SetIntValue( nValue );
  2948. }
  2949. return bFound;
  2950. }
  2951. void DoDepthOfField( const CViewSetup &view )
  2952. {
  2953. if ( !IsDepthOfFieldEnabled() )
  2954. {
  2955. return;
  2956. }
  2957. // Copy from backbuffer to _rt_FullFrameFB
  2958. UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height, false ); // Do we need to check if we already did this?
  2959. CMatRenderContextPtr pRenderContext( materials );
  2960. ITexture *pSrc = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  2961. int nSrcWidth = pSrc->GetActualWidth();
  2962. int nSrcHeight = pSrc->GetActualHeight();
  2963. if ( mat_dof_quality.GetInt() < 2 )
  2964. {
  2965. /////////////////////////////////////
  2966. // Downsample backbuffer to 1/4 size
  2967. /////////////////////////////////////
  2968. // Update downsampled framebuffer. TODO: Don't do this again for the bloom if we already did it here...
  2969. pRenderContext->PushRenderTargetAndViewport();
  2970. ITexture *dest_rt0 = materials->FindTexture( "_rt_SmallFB0", TEXTURE_GROUP_RENDER_TARGET );
  2971. // *Everything* in here relies on the small RTs being exactly 1/4 the full FB res
  2972. Assert( dest_rt0->GetActualWidth() == pSrc->GetActualWidth() / 4 );
  2973. Assert( dest_rt0->GetActualHeight() == pSrc->GetActualHeight() / 4 );
  2974. // Downsample fb to rt0
  2975. DownsampleFBQuarterSize( pRenderContext, nSrcWidth, nSrcHeight, dest_rt0, true );
  2976. //////////////////////////////////////
  2977. // Additional blur using 3x3 Gaussian
  2978. //////////////////////////////////////
  2979. IMaterial *pMat = materials->FindMaterial( "dev/blurgaussian_3x3", TEXTURE_GROUP_OTHER, true );
  2980. if ( pMat == NULL )
  2981. return;
  2982. SetMaterialVarFloat( pMat, "$c0_x", 0.5f / (float)dest_rt0->GetActualWidth() );
  2983. SetMaterialVarFloat( pMat, "$c0_y", 0.5f / (float)dest_rt0->GetActualHeight() );
  2984. SetMaterialVarFloat( pMat, "$c1_x", -0.5f / (float)dest_rt0->GetActualWidth() );
  2985. SetMaterialVarFloat( pMat, "$c1_y", 0.5f / (float)dest_rt0->GetActualHeight() );
  2986. ITexture *dest_rt1 = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  2987. SetRenderTargetAndViewPort( dest_rt1 );
  2988. pRenderContext->DrawScreenSpaceRectangle(
  2989. pMat, 0, 0, nSrcWidth/4, nSrcHeight/4,
  2990. 0, 0, dest_rt0->GetActualWidth()-1, dest_rt0->GetActualHeight()-1,
  2991. dest_rt0->GetActualWidth(), dest_rt0->GetActualHeight() );
  2992. if ( IsGameConsole() )
  2993. {
  2994. pRenderContext->CopyRenderTargetToTextureEx( dest_rt1, 0, NULL, NULL );
  2995. }
  2996. pRenderContext->PopRenderTargetAndViewport();
  2997. }
  2998. // Render depth-of-field quad
  2999. int nViewportWidth = 0;
  3000. int nViewportHeight = 0;
  3001. int nDummy = 0;
  3002. pRenderContext->GetViewport( nDummy, nDummy, nViewportWidth, nViewportHeight );
  3003. IMaterial *pMatDOF = materials->FindMaterial( "dev/depth_of_field", TEXTURE_GROUP_OTHER, true );
  3004. if ( pMatDOF == NULL )
  3005. return;
  3006. SetMaterialVarFloat( pMatDOF, "$nearPlane", view.zNear );
  3007. SetMaterialVarFloat( pMatDOF, "$farPlane", view.zFar );
  3008. // Only SFM drives this bool at the moment...
  3009. if ( view.m_bDoDepthOfField )
  3010. {
  3011. SetMaterialVarFloat( pMatDOF, "$nearBlurDepth", view.m_flNearBlurDepth );
  3012. SetMaterialVarFloat( pMatDOF, "$nearFocusDepth", view.m_flNearFocusDepth );
  3013. SetMaterialVarFloat( pMatDOF, "$farFocusDepth", view.m_flFarFocusDepth );
  3014. SetMaterialVarFloat( pMatDOF, "$farBlurDepth", view.m_flFarBlurDepth );
  3015. SetMaterialVarFloat( pMatDOF, "$nearBlurRadius", view.m_flNearBlurRadius );
  3016. SetMaterialVarFloat( pMatDOF, "$farBlurRadius", view.m_flFarBlurRadius );
  3017. SetMaterialVarInt( pMatDOF, "$quality", view.m_nDoFQuality );
  3018. }
  3019. else // pull from convars/globals
  3020. {
  3021. SetMaterialVarFloat( pMatDOF, "$nearBlurDepth", GetNearBlurDepth() );
  3022. SetMaterialVarFloat( pMatDOF, "$nearFocusDepth", GetNearFocusDepth() );
  3023. SetMaterialVarFloat( pMatDOF, "$farFocusDepth", GetFarFocusDepth() );
  3024. SetMaterialVarFloat( pMatDOF, "$farBlurDepth", GetFarBlurDepth() );
  3025. SetMaterialVarFloat( pMatDOF, "$nearBlurRadius", GetNearBlurRadius() );
  3026. SetMaterialVarFloat( pMatDOF, "$farBlurRadius", GetFarBlurRadius() );
  3027. SetMaterialVarInt( pMatDOF, "$quality", mat_dof_quality.GetInt() );
  3028. }
  3029. pRenderContext->DrawScreenSpaceRectangle(
  3030. pMatDOF,
  3031. 0, 0, nViewportWidth, nViewportHeight,
  3032. 0, 0, nSrcWidth-1, nSrcHeight-1,
  3033. nSrcWidth, nSrcHeight, GetClientWorldEntity()->GetClientRenderable() );
  3034. }
  3035. void DrawModulationQuad( IMaterial *pMaterial, IMatRenderContext *pRenderContext, uint8 r, uint8 g, uint8 b, uint8 a, float fDepth )
  3036. {
  3037. pRenderContext->EnableClipping( false );
  3038. pRenderContext->Bind( pMaterial );
  3039. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  3040. pRenderContext->MatrixMode( MATERIAL_MODEL );
  3041. pRenderContext->PushMatrix();
  3042. pRenderContext->LoadIdentity();
  3043. pRenderContext->MatrixMode( MATERIAL_VIEW );
  3044. pRenderContext->PushMatrix();
  3045. pRenderContext->LoadIdentity();
  3046. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  3047. pRenderContext->PushMatrix();
  3048. pRenderContext->LoadIdentity();
  3049. int w, h;
  3050. pRenderContext->GetRenderTargetDimensions( w, h );
  3051. if ( ( w == 0 ) || ( h == 0 ) )
  3052. return;
  3053. // This is the size of the back-buffer we're reading from.
  3054. int bw, bh;
  3055. bw = w; bh = h;
  3056. float s0, t0;
  3057. float s1, t1;
  3058. float flOffsetS = (bw != 0.0f) ? 1.0f / bw : 0.0f;
  3059. float flOffsetT = (bh != 0.0f) ? 1.0f / bh : 0.0f;
  3060. s0 = 0.5f * flOffsetS;
  3061. t0 = 0.5f * flOffsetT;
  3062. s1 = (w-0.5f) * flOffsetS;
  3063. t1 = (h-0.5f) * flOffsetT;
  3064. CMeshBuilder meshBuilder;
  3065. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  3066. meshBuilder.Position3f( -1.0f, -1.0f, fDepth );
  3067. //meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  3068. //meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  3069. //meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  3070. meshBuilder.TexCoord2f( 0, s0, t1 );
  3071. meshBuilder.Color4ub( r, g, b, a );
  3072. meshBuilder.AdvanceVertex();
  3073. meshBuilder.Position3f( -1.0f, 1, fDepth );
  3074. //meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  3075. //meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  3076. //meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  3077. meshBuilder.TexCoord2f( 0, s0, t0 );
  3078. meshBuilder.Color4ub( r, g, b, a );
  3079. meshBuilder.AdvanceVertex();
  3080. meshBuilder.Position3f( 1, 1, fDepth );
  3081. //meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  3082. //meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  3083. //meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  3084. meshBuilder.TexCoord2f( 0, s1, t0 );
  3085. meshBuilder.Color4ub( r, g, b, a );
  3086. meshBuilder.AdvanceVertex();
  3087. meshBuilder.Position3f( 1, -1.0f, fDepth );
  3088. //meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  3089. //meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  3090. //meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  3091. meshBuilder.TexCoord2f( 0, s1, t1 );
  3092. meshBuilder.Color4ub( r, g, b, a );
  3093. meshBuilder.AdvanceVertex();
  3094. meshBuilder.End();
  3095. pMesh->Draw();
  3096. pRenderContext->MatrixMode( MATERIAL_MODEL );
  3097. pRenderContext->PopMatrix();
  3098. pRenderContext->MatrixMode( MATERIAL_VIEW );
  3099. pRenderContext->PopMatrix();
  3100. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  3101. pRenderContext->PopMatrix();
  3102. pRenderContext->EnableClipping( true );
  3103. }
  3104. ConVar cl_blurClearAlpha( "cl_blurClearAlpha", "0", 0, "0-255, but 0 has errors at the moment" );
  3105. ConVar cl_blurDebug( "cl_blurDebug", "0" );
  3106. ConVar cl_blurTapSize( "cl_blurTapSize", "0.5" );
  3107. ConVar cl_blurPasses( "cl_blurPasses", "1" );
  3108. void BlurEntity( IClientRenderable *pRenderable, bool bPreDraw, int drawFlags, const RenderableInstance_t &instance, const CViewSetup &view, int x, int y, int w, int h )
  3109. {
  3110. ITexture *pFullFrameFB = materials->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  3111. ITexture *dest_rt[2];
  3112. dest_rt[0] = materials->FindTexture( "_rt_SmallFB0", TEXTURE_GROUP_RENDER_TARGET );
  3113. dest_rt[1] = materials->FindTexture( "_rt_SmallFB1", TEXTURE_GROUP_RENDER_TARGET );
  3114. IMaterial *pBlurPass[2];
  3115. pBlurPass[0] = materials->FindMaterial( "dev/blurentity_blurpass0", TEXTURE_GROUP_OTHER );
  3116. pBlurPass[1] = materials->FindMaterial( "dev/blurentity_blurpass1", TEXTURE_GROUP_OTHER );
  3117. IMaterial *pEntBlurCopyBack[2];
  3118. pEntBlurCopyBack[0] = materials->FindMaterial( "dev/blurentity_copyback0", TEXTURE_GROUP_OTHER );
  3119. pEntBlurCopyBack[1] = materials->FindMaterial( "dev/blurentity_copyback1", TEXTURE_GROUP_OTHER );
  3120. IMaterial *pEntBlurAlphaSilhoutte = materials->FindMaterial( "dev/blurentity_alphasilhoutte", TEXTURE_GROUP_OTHER );
  3121. if( !pFullFrameFB ||
  3122. !dest_rt[0] || !dest_rt[1] ||
  3123. !pBlurPass[0] || !pBlurPass[1] ||
  3124. !pEntBlurCopyBack[0] || !pEntBlurCopyBack[1] ||
  3125. !pEntBlurAlphaSilhoutte )
  3126. {
  3127. return; //missing a vital texture/material
  3128. }
  3129. // Copy from backbuffer to _rt_FullFrameFB
  3130. UpdateScreenEffectTexture( 0, x, y, w, h, true ); // Do we need to check if we already did this?
  3131. CMatRenderContextPtr pRenderContext( materials );
  3132. pRenderContext->PushRenderTargetAndViewport();
  3133. int nSrcWidth = pFullFrameFB->GetActualWidth();
  3134. int nSrcHeight = pFullFrameFB->GetActualHeight();
  3135. pRenderContext->OverrideAlphaWriteEnable( true, true ); //ensure we're always copying alpha values in every shader since we're using alpha as a mask when drawing to the back buffer
  3136. //replace the alpha channel with a silhoutte of the desired entity. We'll use the blurred alpha when rendering back to the back buffer
  3137. {
  3138. SetRenderTargetAndViewPort( pFullFrameFB );
  3139. pRenderContext->ClearColor4ub( 255, 255, 255, cl_blurClearAlpha.GetInt() );
  3140. pRenderContext->ClearBuffersObeyStencilEx( cl_blurDebug.GetBool(), true, true ); //clear out the existing alpha and depth
  3141. if( bPreDraw ) //in pre-draw mode, this renderable hasn't drawn it's colors anywhere yet, add them to _rt_FullFrameFB
  3142. pRenderable->DrawModel( drawFlags, instance );
  3143. //just write 1.0 to alpha, don't alter color information
  3144. if( !cl_blurDebug.GetBool() )
  3145. pRenderContext->OverrideColorWriteEnable( true, false );
  3146. modelrender->ForcedMaterialOverride( pEntBlurAlphaSilhoutte );
  3147. pRenderable->DrawModel( drawFlags, instance );
  3148. modelrender->ForcedMaterialOverride( NULL );
  3149. if( !cl_blurDebug.GetBool() )
  3150. pRenderContext->OverrideColorWriteEnable( false, false );
  3151. }
  3152. IMaterial *pEntBlurCopyBackFinal = NULL; //the material to use when copying the blur back to the backbuffer
  3153. //generate blur texture
  3154. {
  3155. /////////////////////////////////////
  3156. // Downsample backbuffer to 1/4 size
  3157. /////////////////////////////////////
  3158. // *Everything* in here relies on the small RTs being exactly 1/4 the full FB res
  3159. Assert( dest_rt[0]->GetActualWidth() == pFullFrameFB->GetActualWidth() / 4 );
  3160. Assert( dest_rt[0]->GetActualHeight() == pFullFrameFB->GetActualHeight() / 4 );
  3161. // Downsample fb to rt0
  3162. DownsampleFBQuarterSize( pRenderContext, nSrcWidth, nSrcHeight, dest_rt[0], true );
  3163. //////////////////////////////////////
  3164. // Additional blur
  3165. //////////////////////////////////////
  3166. float flBlurTapSize = cl_blurTapSize.GetFloat();
  3167. for( int i = 0; i != 2; ++i )
  3168. {
  3169. SetMaterialVarFloat( pBlurPass[i], "$c0_x", flBlurTapSize / (float)dest_rt[i]->GetActualWidth() );
  3170. SetMaterialVarFloat( pBlurPass[i], "$c0_y", flBlurTapSize / (float)dest_rt[i]->GetActualHeight() );
  3171. }
  3172. int iBlurPasses = cl_blurPasses.GetInt();
  3173. for( int i = 0; i < iBlurPasses; ++i )
  3174. {
  3175. int iSrc = i & 1;
  3176. int iDest = 1 - iSrc;
  3177. SetRenderTargetAndViewPort( dest_rt[iDest] );
  3178. pRenderContext->DrawScreenSpaceRectangle(
  3179. pBlurPass[iSrc], 0, 0, nSrcWidth/4, nSrcHeight/4,
  3180. 0, 0, dest_rt[iSrc]->GetActualWidth()-1, dest_rt[iSrc]->GetActualHeight()-1,
  3181. dest_rt[iSrc]->GetActualWidth(), dest_rt[iSrc]->GetActualHeight() );
  3182. if ( IsGameConsole() )
  3183. {
  3184. pRenderContext->CopyRenderTargetToTextureEx( dest_rt[iDest], 0, NULL, NULL );
  3185. }
  3186. }
  3187. pEntBlurCopyBackFinal = pEntBlurCopyBack[iBlurPasses & 1];
  3188. }
  3189. pRenderContext->OverrideAlphaWriteEnable( false, true );
  3190. pRenderContext->PopRenderTargetAndViewport();
  3191. //render back to the screen. We use the depth of the closest bbox point as our quad depth
  3192. {
  3193. const Vector &vRenderOrigin = pRenderable->GetRenderOrigin();
  3194. const QAngle &qRenderAngles = pRenderable->GetRenderAngles();
  3195. Vector vMins, vMaxs;
  3196. pRenderable->GetRenderBounds( vMins, vMaxs );
  3197. VMatrix matWorld, matView, matProj, matWorldView, matWorldViewProj;
  3198. //since the model matrix isn't necessarily set for this renderable, construct it manually
  3199. matWorld.SetupMatrixOrgAngles( vRenderOrigin, qRenderAngles );
  3200. pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
  3201. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
  3202. MatrixMultiply( matView, matWorld, matWorldView );
  3203. MatrixMultiply( matProj, matWorldView, matWorldViewProj );
  3204. float fClosestBBoxDepth = 1.0f;
  3205. Vector4D vTest;
  3206. vTest.w = 1.0f;
  3207. for( int i = 0; i != 8; ++i )
  3208. {
  3209. vTest.x = (i & (1 << 0)) ? vMaxs.x : vMins.x;
  3210. vTest.y = (i & (1 << 1)) ? vMaxs.y : vMins.y;
  3211. vTest.z = (i & (1 << 2)) ? vMaxs.z : vMins.z;
  3212. Vector4D vOut;
  3213. matWorldViewProj.V4Mul( vTest, vOut );
  3214. float fDepth = vOut.z/vOut.w;
  3215. if( fDepth < fClosestBBoxDepth )
  3216. fClosestBBoxDepth = fDepth;
  3217. }
  3218. if( fClosestBBoxDepth < 0.0f )
  3219. fClosestBBoxDepth = 0.0f;
  3220. DrawModulationQuad( pEntBlurCopyBackFinal, pRenderContext, 255, 255, 255, 255, fClosestBBoxDepth );
  3221. }
  3222. if( bPreDraw && ( instance.m_nAlpha == 255 ) && ( ( drawFlags & STUDIO_TRANSPARENCY ) == 0 ) ) //write depth out to the depth buffer
  3223. {
  3224. modelrender->ForcedMaterialOverride( NULL, OVERRIDE_DEPTH_WRITE );
  3225. pRenderable->DrawModel( drawFlags, instance );
  3226. modelrender->ForcedMaterialOverride( NULL );
  3227. }
  3228. }
  3229. ConVar cl_teamid( "cl_teamid", "0" );
  3230. class CTeamIdMaterialProxy : public CEntityMaterialProxy
  3231. {
  3232. public:
  3233. CTeamIdMaterialProxy()
  3234. {
  3235. m_pMaterial = NULL;
  3236. m_pVar = NULL;
  3237. }
  3238. virtual ~CTeamIdMaterialProxy()
  3239. {
  3240. }
  3241. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  3242. {
  3243. m_pMaterial = pMaterial;
  3244. bool found;
  3245. m_pVar = m_pMaterial->FindVar( "$SelfIllumFresnelEnabledThisFrame", &found );
  3246. if ( !found )
  3247. {
  3248. m_pVar = NULL;
  3249. return false;
  3250. }
  3251. return true;
  3252. }
  3253. virtual void OnBind( C_BaseEntity *pC_BaseEntity )
  3254. {
  3255. if ( cl_teamid.GetInt() == 0 )
  3256. {
  3257. m_pVar->SetIntValue( 0 );
  3258. return;
  3259. }
  3260. if ( pC_BaseEntity->InLocalTeam() )
  3261. {
  3262. m_pVar->SetIntValue( 1 );
  3263. }
  3264. else
  3265. {
  3266. m_pVar->SetIntValue( 0 );
  3267. }
  3268. }
  3269. virtual IMaterial *GetMaterial()
  3270. {
  3271. return m_pMaterial;
  3272. }
  3273. protected:
  3274. IMaterial *m_pMaterial;
  3275. IMaterialVar *m_pVar;
  3276. };
  3277. EXPOSE_MATERIAL_PROXY( CTeamIdMaterialProxy, TeamIdMaterialProxy );