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.

701 lines
21 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "render_pch.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. #include "r_areaportal.h"
  12. #include "coordsize.h"
  13. // Leaf visualization routines
  14. // Draw groups can be enabled/disabled for visualization using a bitfield specified by mat_leafvis_draw_mask;
  15. // e.g. -1 = draw all, bit N set = draw group N, so '5' corresponds to draw group 0 and 2 only since 5 = (1 << 0) + (1 << 2)
  16. enum DrawGroup_t
  17. {
  18. DG_BASE = 0,
  19. DG_PVS_VISIBLE_LEAVES = 0,
  20. DG_FRUSTUM_VISIBLE_LEAVES = 1,
  21. DG_FRUSTUM = 2,
  22. DG_PVS_INVISIBLE_LEAVES = 3,
  23. MAX_DRAW_GROUPS = 4,
  24. };
  25. void CSGFrustum( Frustum_t &frustum );
  26. struct leafvis_t
  27. {
  28. leafvis_t()
  29. {
  30. memset( &m_Colors, 0, sizeof( m_Colors ) );
  31. leafIndex = 0;
  32. CCollisionBSPData *pBSP = GetCollisionBSPData();
  33. if ( pBSP )
  34. {
  35. numbrushes = pBSP->numbrushes;
  36. numentitychars = pBSP->numentitychars;
  37. }
  38. }
  39. bool IsValid()
  40. {
  41. CCollisionBSPData *pBSP = GetCollisionBSPData();
  42. if ( !pBSP || numbrushes != pBSP->numbrushes || numentitychars != pBSP->numentitychars )
  43. return false;
  44. return true;
  45. }
  46. CUtlVector<Vector> verts;
  47. struct Polygon_t
  48. {
  49. Polygon_t( int nVertCount, DrawGroup_t drawGroup = DG_BASE ) :
  50. m_nVertCount( nVertCount ),
  51. m_DrawGroup( drawGroup )
  52. {
  53. }
  54. int m_nVertCount;
  55. DrawGroup_t m_DrawGroup;
  56. };
  57. CUtlVector< Polygon_t > m_Polygons;
  58. Vector m_Colors[MAX_DRAW_GROUPS];
  59. int numbrushes;
  60. int numentitychars;
  61. int leafIndex;
  62. };
  63. const int MAX_LEAF_PVERTS = 128;
  64. // Only allocate this after it is turned on
  65. leafvis_t *g_LeafVis = NULL;
  66. leafvis_t *g_FrustumVis = NULL, *g_ClipVis[4] = {NULL,NULL,NULL,NULL};
  67. static void AddPlaneToList( CUtlVector<cplane_t> &list, const Vector& normal, float dist, int invert )
  68. {
  69. cplane_t plane;
  70. plane.dist = invert ? -dist : dist;
  71. plane.normal = invert ? -normal : normal;
  72. Vector point = plane.dist * plane.normal;
  73. for ( int i = 0; i < list.Count(); i++ )
  74. {
  75. // same plane, remove or replace
  76. if ( list[i].normal == plane.normal )
  77. {
  78. float d = DotProduct(point, list[i].normal) - list[i].dist;
  79. if ( d > 0 )
  80. {
  81. // new plane is in front of the old one
  82. list[i].dist = plane.dist;
  83. }
  84. // new plane is behind the old one
  85. return;
  86. }
  87. }
  88. list.AddToTail( plane );
  89. }
  90. static void PlaneList( int leafIndex, model_t *model, CUtlVector<cplane_t> &planeList )
  91. {
  92. if (!model || !model->brush.pShared || !model->brush.pShared->nodes)
  93. Sys_Error ("PlaneList: bad model");
  94. mleaf_t *pLeaf = &model->brush.pShared->leafs[leafIndex];
  95. mnode_t *pNode = pLeaf->parent;
  96. mnode_t *pChild = (mnode_t *)pLeaf;
  97. while (pNode)
  98. {
  99. // was the child on the front or back of the plane of this node?
  100. bool front = (pNode->children[0] == pChild) ? true : false;
  101. AddPlaneToList( planeList, pNode->plane->normal, pNode->plane->dist, !front );
  102. pChild = pNode;
  103. pNode = pNode->parent;
  104. }
  105. }
  106. Vector CSGInsidePoint( cplane_t *pPlanes, int planeCount )
  107. {
  108. Vector point = vec3_origin;
  109. for ( int i = 0; i < planeCount; i++ )
  110. {
  111. float d = DotProduct( pPlanes[i].normal, point ) - pPlanes[i].dist;
  112. if ( d < 0 )
  113. {
  114. point -= d * pPlanes[i].normal;
  115. }
  116. }
  117. return point;
  118. }
  119. void TranslatePlaneList( cplane_t *pPlanes, int planeCount, const Vector &offset )
  120. {
  121. for ( int i = 0; i < planeCount; i++ )
  122. {
  123. pPlanes[i].dist += DotProduct( offset, pPlanes[i].normal );
  124. }
  125. }
  126. void CSGPlaneList( leafvis_t *pVis, CUtlVector<cplane_t> &planeList, DrawGroup_t drawGroup = DG_BASE )
  127. {
  128. int planeCount = planeList.Count();
  129. Vector vertsIn[MAX_LEAF_PVERTS], vertsOut[MAX_LEAF_PVERTS];
  130. // compute a point inside the volume defined by these planes
  131. Vector insidePoint = CSGInsidePoint( planeList.Base(), planeList.Count() );
  132. // move the planes so that the inside point is at the origin
  133. // NOTE: This is to maximize precision for the CSG operations
  134. TranslatePlaneList( planeList.Base(), planeList.Count(), -insidePoint );
  135. // Build the CSG solid of this leaf given that the planes in the list define a convex solid
  136. for ( int i = 0; i < planeCount; i++ )
  137. {
  138. // Build a big-ass poly in this plane
  139. int vertCount = PolyFromPlane( vertsIn, planeList[i].normal, planeList[i].dist ); // BaseWindingForPlane()
  140. // Now chop it by every other plane
  141. int j;
  142. for ( j = 0; j < planeCount; j++ )
  143. {
  144. // don't clip planes with themselves
  145. if ( i == j )
  146. continue;
  147. // Less than a poly left, something's wrong, don't bother with this polygon
  148. if ( vertCount < 3 )
  149. continue;
  150. // Chop the polygon against this plane
  151. vertCount = ClipPolyToPlane( vertsIn, vertCount, vertsOut, planeList[j].normal, planeList[j].dist );
  152. // Just copy the verts each time, don't bother swapping pointers (efficiency is not a goal here)
  153. for ( int k = 0; k < vertCount; k++ )
  154. {
  155. VectorCopy( vertsOut[k], vertsIn[k] );
  156. }
  157. }
  158. // We've got a polygon here
  159. if ( vertCount >= 3 )
  160. {
  161. // Copy polygon out
  162. pVis->m_Polygons.AddToTail( leafvis_t::Polygon_t( vertCount, drawGroup ) );
  163. for ( j = 0; j < vertCount; j++ )
  164. {
  165. // move the verts back by the initial translation
  166. Vector vert = vertsIn[j] + insidePoint;
  167. pVis->verts.AddToTail( vert );
  168. }
  169. }
  170. }
  171. }
  172. void LeafvisChanged( IConVar *pLeafvisVar, const char *pOld, float flOldValue )
  173. {
  174. if ( g_LeafVis )
  175. {
  176. delete g_LeafVis;
  177. g_LeafVis = NULL;
  178. }
  179. if ( g_FrustumVis )
  180. {
  181. delete g_FrustumVis;
  182. g_FrustumVis = NULL;
  183. }
  184. }
  185. void AddLeafPortals( leafvis_t *pLeafvis, int leafIndex, DrawGroup_t drawGroup = DG_BASE )
  186. {
  187. CUtlVector<cplane_t> planeList;
  188. Vector normal;
  189. // Build a list of inward pointing planes of the tree descending to this
  190. PlaneList( leafIndex, host_state.worldmodel, planeList );
  191. VectorCopy( vec3_origin, normal );
  192. // Add world bounding box planes in case the world isn't closed
  193. // x-axis
  194. normal[0] = 1;
  195. AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true );
  196. AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false );
  197. normal[0] = 0;
  198. // y-axis
  199. normal[1] = 1;
  200. AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true );
  201. AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false );
  202. normal[1] = 0;
  203. // z-axis
  204. normal[2] = 1;
  205. AddPlaneToList( planeList, normal, MAX_COORD_INTEGER, true );
  206. AddPlaneToList( planeList, normal, -MAX_COORD_INTEGER, false );
  207. CSGPlaneList( pLeafvis, planeList, drawGroup );
  208. }
  209. ConVar mat_leafvis("mat_leafvis","0", FCVAR_CHEAT, "Draw wireframe of: [0] nothing, [1] current leaf, [2] entire vis cluster, or [3] entire PVS (see mat_leafvis_draw_mask for what does/doesn't get drawn)", LeafvisChanged );
  210. ConVar mat_leafvis_update_every_frame( "mat_leafvis_update_every_frame", "0", 0, "Updates leafvis debug render every frame (expensive)" );
  211. ConVar r_visambient("r_visambient","0", 0, "Draw leaf ambient lighting samples. Needs mat_leafvis 1 to work" );
  212. ConVar mat_leafvis_draw_mask( "mat_leafvis_draw_mask", "3", 0, "A bitfield which affects leaf visibility debug rendering. -1: show all, bit 0: render PVS-visible leafs, bit 1: render PVS- and frustum-visible leafs, bit 2: render frustum bounds, bit 3: render leaves out of PVS." );
  213. ConVar mat_leafvis_freeze( "mat_leafvis_freeze", "0", 0, "If set to 1, uses the last known leaf visibility data for visualization. If set to 0, updates based on camera movement." );
  214. //-----------------------------------------------------------------------------
  215. // Purpose: Builds a convex polyhedron of the leaf boundary around p
  216. // Input : p - point to classify determining the leaf
  217. //-----------------------------------------------------------------------------
  218. void LeafVisBuild( const Vector &p )
  219. {
  220. if ( !mat_leafvis.GetInt() )
  221. {
  222. Assert( !g_LeafVis );
  223. return;
  224. }
  225. else
  226. {
  227. static int last_leaf = -1;
  228. int leafIndex = CM_PointLeafnum( p );
  229. if ( mat_leafvis_freeze.GetBool() && last_leaf != -1 && last_leaf < host_state.worldmodel->brush.pShared->numleafs )
  230. {
  231. leafIndex = last_leaf;
  232. }
  233. if ( g_LeafVis && ( last_leaf == leafIndex ) && !mat_leafvis_update_every_frame.GetBool() )
  234. return;
  235. bool bSpewOnLeafChanged = ( last_leaf != leafIndex );
  236. if ( bSpewOnLeafChanged )
  237. {
  238. DevMsg( 1, "Leaf %d, Area %d, Cluster %d\n", leafIndex, CM_LeafArea( leafIndex ), CM_LeafCluster( leafIndex ) );
  239. }
  240. last_leaf = leafIndex;
  241. delete g_LeafVis;
  242. g_LeafVis = new leafvis_t;
  243. // Color for leafs in PVS
  244. g_LeafVis->m_Colors[DG_PVS_VISIBLE_LEAVES].Init( 0.0f, 0.0f, 1.0f );
  245. // Color for leafs in PVS that pass frustum test
  246. g_LeafVis->m_Colors[DG_FRUSTUM_VISIBLE_LEAVES].Init( 0.0f, 0.0f, 1.0f );
  247. g_LeafVis->m_Colors[DG_PVS_INVISIBLE_LEAVES].Init( 0.5f, 1.0f, 0.0f );
  248. // Color for frustum is set by CSGFrustum()
  249. g_LeafVis->leafIndex = leafIndex;
  250. switch( mat_leafvis.GetInt() )
  251. {
  252. case 2:
  253. {
  254. const mleaf_t *pLeaf = host_state.worldmodel->brush.pShared->leafs;
  255. int leafCount = host_state.worldmodel->brush.pShared->numleafs;
  256. int visCluster = pLeaf[leafIndex].cluster;
  257. // do entire viscluster
  258. for ( int i = 0; i < leafCount; i++ )
  259. {
  260. if ( pLeaf[i].cluster == visCluster )
  261. {
  262. AddLeafPortals( g_LeafVis, i );
  263. }
  264. }
  265. }
  266. break;
  267. case 3:
  268. {
  269. // do entire pvs
  270. byte pvs[ MAX_MAP_LEAFS/8 ];
  271. const mleaf_t *pLeaf = host_state.worldmodel->brush.pShared->leafs;
  272. int leafCount = host_state.worldmodel->brush.pShared->numleafs;
  273. int visCluster = pLeaf[leafIndex].cluster;
  274. CM_Vis( pvs, sizeof( pvs ), visCluster, DVIS_PVS );
  275. const CViewSetup &view = g_EngineRenderer->ViewGetCurrent();
  276. Frustum_t frustum;
  277. GeneratePerspectiveFrustum( g_EngineRenderer->ViewOrigin(), g_EngineRenderer->ViewAngles(), g_EngineRenderer->GetZNear(), g_EngineRenderer->GetZFar(), g_EngineRenderer->GetFov(), view.m_flAspectRatio, frustum );
  278. // Add frustum faces to render list in draw group DG_FRUSTUM
  279. CSGFrustum( frustum );
  280. int nPVSLeafCount = 0, nFrustumLeafCount = 0, nOutOfPVSCount = 0;
  281. for ( int i = 0; i < leafCount; i++ )
  282. {
  283. int cluster = pLeaf[i].cluster;
  284. if ( cluster >= 0 )
  285. {
  286. if ( pLeaf[i].m_vecHalfDiagonal.x < DIST_EPSILON || pLeaf[i].m_vecHalfDiagonal.y < DIST_EPSILON || pLeaf[i].m_vecHalfDiagonal.z < DIST_EPSILON )
  287. {
  288. // 0-volume leaf, ignore
  289. continue;
  290. }
  291. if ( (pvs[cluster>>3] & (1<<(cluster&7))) )
  292. {
  293. ++ nPVSLeafCount;
  294. bool bIsVisible = !CullNodeSIMD( frustum, ( mnode_t * )( &pLeaf[i] ) );
  295. if ( bIsVisible )
  296. {
  297. ++ nFrustumLeafCount;
  298. }
  299. // Add leaf portals to a different draw group based on whether they pass the frustum test (and are in PVS) or are simply in the PVS but not in the frustum
  300. AddLeafPortals( g_LeafVis, i, bIsVisible ? DG_FRUSTUM_VISIBLE_LEAVES : DG_PVS_VISIBLE_LEAVES );
  301. }
  302. else
  303. {
  304. ++ nOutOfPVSCount;
  305. // Add leaf portals to a different draw group based on whether they pass the frustum test (and are in PVS) or are simply in the PVS but not in the frustum
  306. AddLeafPortals( g_LeafVis, i, DG_PVS_INVISIBLE_LEAVES );
  307. }
  308. }
  309. }
  310. if ( bSpewOnLeafChanged )
  311. {
  312. DevMsg( 1, "%d Leaves in PVS, %d visible, %d outside of PVS\n", nPVSLeafCount, nFrustumLeafCount, nOutOfPVSCount );
  313. }
  314. }
  315. break;
  316. case 0:
  317. default:
  318. AddLeafPortals( g_LeafVis, leafIndex );
  319. break;
  320. }
  321. }
  322. }
  323. #ifndef DEDICATED
  324. void DrawLeafvis( leafvis_t *pVis )
  325. {
  326. CMatRenderContextPtr pRenderContext( materials );
  327. int nMask = mat_leafvis_draw_mask.GetInt();
  328. for ( int nPass = 0; nPass < MAX_DRAW_GROUPS; ++ nPass )
  329. {
  330. int nVertIndex = 0;
  331. if ( ( ( 1 << nPass ) & nMask ) == 0 )
  332. {
  333. continue;
  334. }
  335. g_materialLeafVisWireframe->ColorModulate( pVis->m_Colors[nPass][0], pVis->m_Colors[nPass][1], pVis->m_Colors[nPass][2] );
  336. pRenderContext->Bind( g_materialLeafVisWireframe );
  337. for ( int i = 0; i < pVis->m_Polygons.Count(); i++ )
  338. {
  339. int nPolygonVertCount = pVis->m_Polygons[i].m_nVertCount;
  340. if ( nPolygonVertCount >= 3 && nPass == pVis->m_Polygons[i].m_DrawGroup )
  341. {
  342. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  343. CMeshBuilder meshBuilder;
  344. meshBuilder.Begin( pMesh, MATERIAL_LINES, nPolygonVertCount );
  345. for ( int j = 0; j < nPolygonVertCount; j++ )
  346. {
  347. meshBuilder.Position3fv( pVis->verts[ nVertIndex + j ].Base() );
  348. meshBuilder.AdvanceVertex();
  349. meshBuilder.Position3fv( pVis->verts[ nVertIndex + ( ( j + 1 ) % nPolygonVertCount ) ].Base() );
  350. meshBuilder.AdvanceVertex();
  351. }
  352. meshBuilder.End();
  353. pMesh->Draw();
  354. }
  355. nVertIndex += nPolygonVertCount;
  356. }
  357. }
  358. }
  359. void DrawLeafvis_Solid( leafvis_t *pVis )
  360. {
  361. CMatRenderContextPtr pRenderContext( materials );
  362. int vert = 0;
  363. Vector lightNormal(1,1,1);
  364. VectorNormalize(lightNormal);
  365. pRenderContext->Bind( g_pMaterialDebugFlat );
  366. for ( int i = 0; i < pVis->m_Polygons.Count(); i++ )
  367. {
  368. int vertCount = pVis->m_Polygons[i].m_nVertCount;
  369. if ( vertCount >= 3 )
  370. {
  371. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  372. CMeshBuilder meshBuilder;
  373. int triangleCount = vertCount-2;
  374. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, triangleCount );
  375. Vector e0 = pVis->verts[vert+1] - pVis->verts[vert];
  376. Vector e1 = pVis->verts[vert+2] - pVis->verts[vert];
  377. Vector normal = CrossProduct(e1,e0);
  378. VectorNormalize( normal );
  379. float light = 0.5f + (DotProduct(normal, lightNormal)*0.5f);
  380. Vector color = pVis->m_Colors[DG_BASE] * light;
  381. for ( int j = 0; j < vertCount; j++ )
  382. {
  383. meshBuilder.Position3fv( pVis->verts[ vert + j ].Base() );
  384. meshBuilder.Color3fv( color.Base() );
  385. meshBuilder.AdvanceVertex();
  386. }
  387. for ( int j = 0; j < triangleCount; j++ )
  388. {
  389. meshBuilder.FastIndex(0);
  390. meshBuilder.FastIndex(j+2);
  391. meshBuilder.FastIndex(j+1);
  392. }
  393. meshBuilder.End();
  394. pMesh->Draw();
  395. }
  396. vert += vertCount;
  397. }
  398. }
  399. int FindMinBrush( CCollisionBSPData *pBSPData, int nodenum, int brushIndex )
  400. {
  401. while (1)
  402. {
  403. if (nodenum < 0)
  404. {
  405. int leafIndex = -1 - nodenum;
  406. cleaf_t &leaf = pBSPData->map_leafs[leafIndex];
  407. int firstbrush = pBSPData->map_leafbrushes[ leaf.firstleafbrush ];
  408. if ( firstbrush < brushIndex )
  409. {
  410. brushIndex = firstbrush;
  411. }
  412. return brushIndex;
  413. }
  414. cnode_t &node = pBSPData->map_rootnode[nodenum];
  415. brushIndex = FindMinBrush( pBSPData, node.children[0], brushIndex );
  416. nodenum = node.children[1];
  417. }
  418. return brushIndex;
  419. }
  420. void RecomputeClipbrushes( bool bEnabled )
  421. {
  422. for ( int v = 0; v < 4; v++ )
  423. {
  424. delete g_ClipVis[v];
  425. g_ClipVis[v] = NULL;
  426. }
  427. if ( !bEnabled )
  428. return;
  429. for ( int v = 0; v < 4; v++ )
  430. {
  431. int contents[4] = {CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP, CONTENTS_MONSTERCLIP, CONTENTS_PLAYERCLIP, CONTENTS_GRENADECLIP};
  432. g_ClipVis[v] = new leafvis_t;
  433. if ( v == 3 )
  434. {
  435. g_ClipVis[v]->m_Colors[DG_BASE].Init( 0.0f, 0.8f, 0.0f );
  436. }
  437. else
  438. {
  439. g_ClipVis[v]->m_Colors[DG_BASE].Init( v != 1 ? 1.0f : 0.5, 0.0f, v != 0 ? 1.0f : 0.0f );
  440. }
  441. CCollisionBSPData *pBSP = GetCollisionBSPData();
  442. int lastBrush = pBSP->numbrushes;
  443. if ( pBSP->numcmodels > 1 )
  444. {
  445. lastBrush = FindMinBrush( pBSP, pBSP->map_cmodels[1].headnode, lastBrush );
  446. }
  447. for ( int i = 0; i < lastBrush; i++ )
  448. {
  449. cbrush_t *pBrush = &pBSP->map_brushes[i];
  450. if ( (pBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_GRENADECLIP)) == contents[v] )
  451. {
  452. CUtlVector<cplane_t> planeList;
  453. if ( pBrush->IsBox() )
  454. {
  455. cboxbrush_t *pBox = &pBSP->map_boxbrushes[pBrush->GetBox()];
  456. for ( int i = 0; i < 3; i++ )
  457. {
  458. Vector normal = vec3_origin;
  459. normal[i] = 1.0f;
  460. AddPlaneToList( planeList, normal, pBox->maxs[i], true );
  461. AddPlaneToList( planeList, -normal, -pBox->mins[i], true );
  462. }
  463. }
  464. else
  465. {
  466. for ( int j = 0; j < pBrush->numsides; j++ )
  467. {
  468. cbrushside_t *pSide = &pBSP->map_brushsides[pBrush->firstbrushside + j];
  469. if ( pSide->bBevel )
  470. continue;
  471. AddPlaneToList( planeList, pSide->plane->normal, pSide->plane->dist, true );
  472. }
  473. }
  474. CSGPlaneList( g_ClipVis[v], planeList );
  475. }
  476. }
  477. }
  478. }
  479. // NOTE: UNDONE: This doesn't work on brush models - only the world.
  480. void ClipChanged( IConVar *pConVar, const char *pOld, float flOldValue )
  481. {
  482. ConVarRef clipVar( pConVar );
  483. RecomputeClipbrushes( clipVar.GetBool() );
  484. }
  485. static ConVar r_drawclipbrushes( "r_drawclipbrushes", "0", FCVAR_CHEAT, "Draw clip brushes (red=NPC+player, pink=player, purple=NPC)", ClipChanged );
  486. static Vector LeafAmbientSamplePos( int leafIndex, const mleafambientlighting_t &sample )
  487. {
  488. mleaf_t *pLeaf = &host_state.worldbrush->leafs[leafIndex];
  489. Vector out = pLeaf->m_vecCenter - pLeaf->m_vecHalfDiagonal;
  490. out.x += float(sample.x) * pLeaf->m_vecHalfDiagonal.x * (2.0f / 255.0f);
  491. out.y += float(sample.y) * pLeaf->m_vecHalfDiagonal.y * (2.0f / 255.0f);
  492. out.z += float(sample.z) * pLeaf->m_vecHalfDiagonal.z * (2.0f / 255.0f);
  493. return out;
  494. }
  495. // convert color formats
  496. static void ColorRGBExp32ToColor32( const ColorRGBExp32 &color, color32 &out )
  497. {
  498. Vector tmp;
  499. ColorRGBExp32ToVector( color, tmp );
  500. out.r = LinearToScreenGamma(tmp.x);
  501. out.g = LinearToScreenGamma(tmp.y);
  502. out.b = LinearToScreenGamma(tmp.z);
  503. }
  504. // some simple helpers to draw a cube in the special way the ambient visualization wants
  505. static Vector CubeSide( const Vector &pos, float size, int vert )
  506. {
  507. Vector side = pos;
  508. side.x += (vert & 1) ? -size : size;
  509. side.y += (vert & 2) ? -size : size;
  510. side.z += (vert & 4) ? -size : size;
  511. return side;
  512. }
  513. static void CubeFace( CMeshBuilder &meshBuilder, const Vector org, int v0, int v1, int v2, int v3, float size, const color32 &color )
  514. {
  515. meshBuilder.Position3fv( CubeSide(org,size,v0).Base() );
  516. meshBuilder.Color4ubv( (byte *)&color );
  517. meshBuilder.AdvanceVertex();
  518. meshBuilder.Position3fv( CubeSide(org,size,v1).Base() );
  519. meshBuilder.Color4ubv( (byte *)&color );
  520. meshBuilder.AdvanceVertex();
  521. meshBuilder.Position3fv( CubeSide(org,size,v2).Base() );
  522. meshBuilder.Color4ubv( (byte *)&color );
  523. meshBuilder.AdvanceVertex();
  524. meshBuilder.Position3fv( CubeSide(org,size,v3).Base() );
  525. meshBuilder.Color4ubv( (byte *)&color );
  526. meshBuilder.AdvanceVertex();
  527. }
  528. //-----------------------------------------------------------------------------
  529. // Purpose: Draw the leaf geometry that was computed by LeafVisBuild()
  530. //-----------------------------------------------------------------------------
  531. void LeafVisDraw( void )
  532. {
  533. if ( g_FrustumVis )
  534. {
  535. DrawLeafvis( g_FrustumVis );
  536. }
  537. if ( g_LeafVis )
  538. {
  539. DrawLeafvis( g_LeafVis );
  540. }
  541. if ( g_ClipVis[0] )
  542. {
  543. if ( !g_ClipVis[0]->IsValid() )
  544. {
  545. RecomputeClipbrushes(true);
  546. }
  547. if ( r_drawclipbrushes.GetInt() == 2 )
  548. {
  549. DrawLeafvis_Solid( g_ClipVis[0] );
  550. DrawLeafvis_Solid( g_ClipVis[1] );
  551. DrawLeafvis_Solid( g_ClipVis[2] );
  552. }
  553. else if ( r_drawclipbrushes.GetInt() == 3 )
  554. {
  555. DrawLeafvis_Solid( g_ClipVis[3] ); // only grenade clip
  556. }
  557. else
  558. {
  559. DrawLeafvis( g_ClipVis[0] );
  560. DrawLeafvis( g_ClipVis[1] );
  561. DrawLeafvis( g_ClipVis[2] );
  562. DrawLeafvis( g_ClipVis[3] );
  563. }
  564. }
  565. if ( g_LeafVis && r_visambient.GetBool() )
  566. {
  567. CMatRenderContextPtr pRenderContext( materials );
  568. pRenderContext->Bind( g_pMaterialDebugFlat );
  569. float cubesize = 12.0f;
  570. int leafIndex = g_LeafVis->leafIndex;
  571. mleafambientindex_t *pAmbient = &host_state.worldbrush->m_pLeafAmbient[leafIndex];
  572. if ( !pAmbient->ambientSampleCount && pAmbient->firstAmbientSample )
  573. {
  574. // this leaf references another leaf, move there (this leaf is a solid leaf so it borrows samples from a neighbor)
  575. leafIndex = pAmbient->firstAmbientSample;
  576. pAmbient = &host_state.worldbrush->m_pLeafAmbient[leafIndex];
  577. }
  578. for ( int i = 0; i < pAmbient->ambientSampleCount; i++ )
  579. {
  580. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  581. CMeshBuilder meshBuilder;
  582. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 6 );
  583. const mleafambientlighting_t &sample = host_state.worldbrush->m_pAmbientSamples[pAmbient->firstAmbientSample+i];
  584. Vector pos = LeafAmbientSamplePos( leafIndex, sample );
  585. // x axis
  586. color32 color;
  587. ColorRGBExp32ToColor32( sample.cube.m_Color[0], color ); // x
  588. CubeFace( meshBuilder, pos, 4, 6, 2, 0, cubesize, color );
  589. ColorRGBExp32ToColor32( sample.cube.m_Color[1], color ); // -x
  590. CubeFace( meshBuilder, pos, 7, 5, 1, 3, cubesize, color );
  591. ColorRGBExp32ToColor32( sample.cube.m_Color[2], color ); // y
  592. CubeFace( meshBuilder, pos, 0, 1, 5, 4, cubesize, color );
  593. ColorRGBExp32ToColor32( sample.cube.m_Color[3], color ); // -y
  594. CubeFace( meshBuilder, pos, 3, 2, 6, 7, cubesize, color );
  595. ColorRGBExp32ToColor32( sample.cube.m_Color[4], color ); // z
  596. CubeFace( meshBuilder, pos, 2, 3, 1, 0, cubesize, color );
  597. ColorRGBExp32ToColor32( sample.cube.m_Color[5], color ); // -z
  598. CubeFace( meshBuilder, pos, 4, 5, 7, 6, cubesize, color );
  599. meshBuilder.End();
  600. pMesh->Draw();
  601. }
  602. }
  603. }
  604. void CSGFrustum( Frustum_t &frustum )
  605. {
  606. delete g_FrustumVis;
  607. g_FrustumVis = new leafvis_t;
  608. g_FrustumVis->m_Colors[DG_FRUSTUM].Init(1.0f, 1.0f, 1.0f);
  609. CUtlVector<cplane_t> planeList;
  610. for ( int i = 0; i < 6; i++ )
  611. {
  612. cplane_t tmp;
  613. tmp.type = PLANE_ANYZ;
  614. frustum.GetPlane(i, &tmp.normal, &tmp.dist);
  615. planeList.AddToTail( tmp );
  616. }
  617. CSGPlaneList( g_FrustumVis, planeList, DG_FRUSTUM );
  618. }
  619. #endif