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.

415 lines
11 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "render_pch.h"
  10. #include "gl_matsysiface.h"
  11. #include "gl_cvars.h"
  12. #include "enginetrace.h"
  13. #include "r_local.h"
  14. #include "gl_model_private.h"
  15. #include "materialsystem/imesh.h"
  16. #include "cdll_engine_int.h"
  17. #include "cl_main.h"
  18. #include "debugoverlay.h"
  19. #include "tier2/renderutils.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. static ConVar r_drawlights( "r_drawlights", "0", FCVAR_CHEAT );
  23. static ConVar r_drawlightinfo( "r_drawlightinfo", "0", FCVAR_CHEAT );
  24. extern ConVar r_lightcache_radiusfactor;
  25. static bool s_bActivateLightSprites = false;
  26. //-----------------------------------------------------------------------------
  27. // Should we draw light sprites over visible lights?
  28. //-----------------------------------------------------------------------------
  29. bool ActivateLightSprites( bool bActive )
  30. {
  31. bool bOldValue = s_bActivateLightSprites;
  32. s_bActivateLightSprites = bActive;
  33. return bOldValue;
  34. }
  35. #define LIGHT_MIN_LIGHT_VALUE 0.03f
  36. float ComputeLightRadius( dworldlight_t *pLight, bool bIsHDR )
  37. {
  38. float flLightRadius = pLight->radius;
  39. if (flLightRadius == 0.0f)
  40. {
  41. // HACKHACK: Usually our designers scale the light intensity by 0.5 in HDR
  42. // This keeps the behavior of the cutoff radius consistent between LDR and HDR
  43. float minLightValue = bIsHDR ? (LIGHT_MIN_LIGHT_VALUE * 0.5f) : LIGHT_MIN_LIGHT_VALUE;
  44. // Compute the light range based on attenuation factors
  45. float flIntensity = sqrtf( DotProduct( pLight->intensity, pLight->intensity ) );
  46. if (pLight->quadratic_attn == 0.0f)
  47. {
  48. if (pLight->linear_attn == 0.0f)
  49. {
  50. // Infinite, but we're not going to draw it as such
  51. flLightRadius = 2000;
  52. }
  53. else
  54. {
  55. flLightRadius = (flIntensity / minLightValue - pLight->constant_attn) / pLight->linear_attn;
  56. }
  57. }
  58. else
  59. {
  60. float a = pLight->quadratic_attn;
  61. float b = pLight->linear_attn;
  62. float c = pLight->constant_attn - flIntensity / minLightValue;
  63. float discrim = b * b - 4 * a * c;
  64. if (discrim < 0.0f)
  65. {
  66. // Infinite, but we're not going to draw it as such
  67. flLightRadius = 2000;
  68. }
  69. else
  70. {
  71. flLightRadius = (-b + sqrtf(discrim)) / (2.0f * a);
  72. if (flLightRadius < 0)
  73. {
  74. flLightRadius = 0;
  75. }
  76. }
  77. }
  78. }
  79. return flLightRadius;
  80. }
  81. static void DrawLightSprite( dworldlight_t *pLight, float angleAttenFactor )
  82. {
  83. Vector lightToEye;
  84. lightToEye = CurrentViewOrigin() - pLight->origin;
  85. VectorNormalize( lightToEye );
  86. Vector up( 0.0f, 0.0f, 1.0f );
  87. Vector right;
  88. CrossProduct( up, lightToEye, right );
  89. VectorNormalize( right );
  90. CrossProduct( lightToEye, right, up );
  91. VectorNormalize( up );
  92. /*
  93. up *= dist;
  94. right *= dist;
  95. up *= ( 1.0f / 5.0f );
  96. right *= ( 1.0f / 5.0f );
  97. up *= 1.0f / sqrt( pLight->constant_attn + dist * pLight->linear_attn + dist * dist * pLight->quadratic_attn );
  98. right *= 1.0f / sqrt( pLight->constant_attn + dist * pLight->linear_attn + dist * dist * pLight->quadratic_attn );
  99. */
  100. // float distFactor = 1.0f / ( pLight->constant_attn + dist * pLight->linear_attn + dist * dist * pLight->quadratic_attn );
  101. //float distFactor = 1.0f;
  102. Vector color = pLight->intensity;
  103. VectorNormalize( color );
  104. color *= angleAttenFactor;
  105. color[0] = pow( color[0], 1.0f / 2.2f );
  106. color[1] = pow( color[1], 1.0f / 2.2f );
  107. color[2] = pow( color[2], 1.0f / 2.2f );
  108. CMatRenderContextPtr pRenderContext( materials );
  109. pRenderContext->Bind( g_pMaterialLightSprite );
  110. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  111. CMeshBuilder meshBuilder;
  112. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  113. float radius = 16.0f;
  114. Vector p;
  115. ColorClamp( color );
  116. p = pLight->origin + right * radius + up * radius;
  117. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  118. meshBuilder.Color3fv( color.Base() );
  119. meshBuilder.Position3fv( p.Base() );
  120. meshBuilder.AdvanceVertex();
  121. p = pLight->origin + right * -radius + up * radius;
  122. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  123. meshBuilder.Color3fv( color.Base() );
  124. meshBuilder.Position3fv( p.Base() );
  125. meshBuilder.AdvanceVertex();
  126. p = pLight->origin + right * -radius + up * -radius;
  127. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  128. meshBuilder.Color3fv( color.Base() );
  129. meshBuilder.Position3fv( p.Base() );
  130. meshBuilder.AdvanceVertex();
  131. p = pLight->origin + right * radius + up * -radius;
  132. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  133. meshBuilder.Color3fv( color.Base() );
  134. meshBuilder.Position3fv( p.Base() );
  135. meshBuilder.AdvanceVertex();
  136. meshBuilder.End();
  137. pMesh->Draw();
  138. }
  139. #define POINT_THETA_GRID 8
  140. #define POINT_PHI_GRID 8
  141. static void DrawPointLight( const Vector &vecOrigin, float flLightRadius )
  142. {
  143. RenderWireframeSphere( vecOrigin, flLightRadius, 8, 8, Color( 0, 255, 255, 255 ), true );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Draws the spot light
  147. //-----------------------------------------------------------------------------
  148. #define SPOT_GRID_LINE_COUNT 20
  149. #define SPOT_GRID_LINE_DISTANCE 50
  150. #define SPOT_RADIAL_GRID 8
  151. void DrawSpotLight( dworldlight_t *pLight )
  152. {
  153. float flLightRadius = ComputeLightRadius( pLight, false );
  154. RenderWireframeSphere( pLight->origin, flLightRadius, 20, 20, Color( 255, 0, 0, 255 ), true );
  155. float flGridLineDist = SPOT_GRID_LINE_DISTANCE;
  156. int nGridLines = (int)(flLightRadius / flGridLineDist) + 1;
  157. if ( nGridLines > 256 )
  158. {
  159. nGridLines = 256;
  160. flGridLineDist = flLightRadius / (float)( nGridLines - 1 );
  161. }
  162. int nVertCount = SPOT_RADIAL_GRID * (nGridLines + 1);
  163. int nIndexCount = 8 * SPOT_RADIAL_GRID * nGridLines;
  164. // Compute a basis perpendicular to the normal
  165. Vector xaxis, yaxis;
  166. int nMinIndex = fabs(pLight->normal[0]) < fabs(pLight->normal[1]) ? 0 : 1;
  167. nMinIndex = fabs(pLight->normal[nMinIndex]) < fabs(pLight->normal[2]) ? nMinIndex : 2;
  168. Vector perp = vec3_origin;
  169. perp[nMinIndex] = 1.0f;
  170. CrossProduct( perp, pLight->normal, xaxis );
  171. VectorNormalize( xaxis );
  172. CrossProduct( pLight->normal, xaxis, yaxis );
  173. CMatRenderContextPtr pRenderContext( materials );
  174. pRenderContext->Bind( g_materialWorldWireframeZBuffer );
  175. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  176. CMeshBuilder meshBuilder;
  177. meshBuilder.Begin( pMesh, MATERIAL_LINES, nVertCount, nIndexCount );
  178. float flAngle = acos(pLight->stopdot2);
  179. float flTanAngle = tan(flAngle);
  180. float dTheta = 360.0f / SPOT_RADIAL_GRID;
  181. float flDist = 0.0f;
  182. int i;
  183. for ( i = 0; i <= nGridLines; ++i )
  184. {
  185. Vector pt, vecCenter;
  186. VectorMA( pLight->origin, flDist, pLight->normal, vecCenter );
  187. float flRadius = flDist * flTanAngle;
  188. float flAngle = 0;
  189. for ( int j = 0; j < SPOT_RADIAL_GRID; ++j )
  190. {
  191. float flSin = sin(DEG2RAD(flAngle));
  192. float flCos = cos(DEG2RAD(flAngle));
  193. VectorMA( vecCenter, flRadius * flCos, xaxis, pt );
  194. VectorMA( pt, flRadius * flSin, yaxis, pt );
  195. meshBuilder.Position3fv( pt.Base() );
  196. meshBuilder.AdvanceVertex();
  197. flAngle += dTheta;
  198. }
  199. flDist += flGridLineDist;
  200. }
  201. for ( i = 0; i < nGridLines; ++i )
  202. {
  203. for ( int j = 0; j < SPOT_RADIAL_GRID; ++j )
  204. {
  205. int nNextIndex = (j != SPOT_RADIAL_GRID - 1) ? j + 1 : 0;
  206. meshBuilder.Index( i * SPOT_RADIAL_GRID + j );
  207. meshBuilder.AdvanceIndex();
  208. meshBuilder.Index( (i + 1) * SPOT_RADIAL_GRID + j );
  209. meshBuilder.AdvanceIndex();
  210. meshBuilder.Index( (i + 1) * SPOT_RADIAL_GRID + j );
  211. meshBuilder.AdvanceIndex();
  212. meshBuilder.Index( (i + 1) * SPOT_RADIAL_GRID + nNextIndex );
  213. meshBuilder.AdvanceIndex();
  214. meshBuilder.Index( (i + 1) * SPOT_RADIAL_GRID + nNextIndex );
  215. meshBuilder.AdvanceIndex();
  216. meshBuilder.Index( i * SPOT_RADIAL_GRID + nNextIndex );
  217. meshBuilder.AdvanceIndex();
  218. meshBuilder.Index( i * SPOT_RADIAL_GRID + nNextIndex );
  219. meshBuilder.AdvanceIndex();
  220. meshBuilder.Index( i * SPOT_RADIAL_GRID + j );
  221. meshBuilder.AdvanceIndex();
  222. }
  223. }
  224. meshBuilder.End();
  225. pMesh->Draw();
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Draws sprites over all visible lights
  229. // NOTE: This is used to render env-cubemaps
  230. //-----------------------------------------------------------------------------
  231. void DrawLightSprites( void )
  232. {
  233. if (!s_bActivateLightSprites)
  234. return;
  235. int i;
  236. for (i = 0; i < host_state.worldbrush->numworldlights; i++)
  237. {
  238. dworldlight_t *pLight = &host_state.worldbrush->worldlights[i];
  239. trace_t tr;
  240. CTraceFilterWorldAndPropsOnly traceFilter;
  241. Ray_t ray;
  242. ray.Init( CurrentViewOrigin(), pLight->origin );
  243. g_pEngineTraceClient->TraceRay( ray, MASK_OPAQUE, &traceFilter, &tr );
  244. if( tr.fraction < 1.0f )
  245. continue;
  246. float angleAttenFactor = 0.0f;
  247. Vector lightToEye;
  248. lightToEye = CurrentViewOrigin() - pLight->origin;
  249. VectorNormalize( lightToEye );
  250. switch( pLight->type )
  251. {
  252. case emit_point:
  253. angleAttenFactor = 1.0f;
  254. break;
  255. case emit_spotlight:
  256. continue;
  257. break;
  258. case emit_surface:
  259. // garymcthack - don't do surface lights
  260. continue;
  261. if( DotProduct( lightToEye, pLight->normal ) < 0.0f )
  262. {
  263. continue;
  264. }
  265. angleAttenFactor = 1.0f;
  266. break;
  267. case emit_skylight:
  268. case emit_skyambient:
  269. continue;
  270. default:
  271. assert( 0 );
  272. continue;
  273. }
  274. DrawLightSprite( pLight, angleAttenFactor );
  275. }
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Draws debugging information for the lights
  279. //-----------------------------------------------------------------------------
  280. void DrawLightDebuggingInfo( void )
  281. {
  282. int i;
  283. char buf[256];
  284. int lineOffset;
  285. int nLight = r_drawlights.GetInt();
  286. if ( r_drawlightinfo.GetBool() )
  287. {
  288. for (i = 0; i < host_state.worldbrush->numworldlights; i++)
  289. {
  290. dworldlight_t *pLight = &host_state.worldbrush->worldlights[i];
  291. lineOffset = 0;
  292. Q_snprintf( buf, sizeof( buf ), "light: %d\n", i+1 );
  293. CDebugOverlay::AddTextOverlay( pLight->origin, lineOffset++, 0, buf );
  294. Q_snprintf( buf, sizeof( buf ), "origin: <%d, %d, %d>\n", (int)pLight->origin[0], (int)pLight->origin[1], (int)pLight->origin[2] );
  295. CDebugOverlay::AddTextOverlay( pLight->origin, lineOffset++, 0, buf );
  296. if (!nLight)
  297. {
  298. // avoid a double debug draw
  299. DrawLightSprite( pLight, 1.0f );
  300. }
  301. }
  302. }
  303. if (!nLight)
  304. return;
  305. for (i = 0; i < host_state.worldbrush->numworldlights; i++)
  306. {
  307. dworldlight_t *pLight = &host_state.worldbrush->worldlights[i];
  308. Vector lightToEye;
  309. float angleAttenFactor = 0.0f;
  310. switch( pLight->type )
  311. {
  312. case emit_point:
  313. angleAttenFactor = 1.0f;
  314. DrawPointLight( pLight->origin, ComputeLightRadius( pLight, false ) );
  315. break;
  316. case emit_spotlight:
  317. angleAttenFactor = 1.0f;
  318. DrawSpotLight( pLight );
  319. break;
  320. case emit_surface:
  321. // garymcthack - don't do surface lights
  322. continue;
  323. lightToEye = CurrentViewOrigin() - pLight->origin;
  324. VectorNormalize( lightToEye );
  325. if( DotProduct( lightToEye, pLight->normal ) < 0.0f )
  326. {
  327. continue;
  328. }
  329. angleAttenFactor = 1.0f;
  330. break;
  331. case emit_skylight:
  332. case emit_skyambient:
  333. continue;
  334. default:
  335. assert( 0 );
  336. continue;
  337. }
  338. DrawLightSprite( pLight, angleAttenFactor );
  339. }
  340. int lnum;
  341. for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
  342. {
  343. // If the light's not active, then continue
  344. if ( (r_dlightactive & (1 << lnum)) == 0 )
  345. continue;
  346. DrawPointLight( cl_dlights[lnum].origin, cl_dlights[lnum].GetRadius() );
  347. }
  348. }