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.

2113 lines
80 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "portalrender.h"
  9. #include "precache_register.h"
  10. #include "view.h"
  11. #include "c_pixel_visibility.h"
  12. #include "glow_overlay.h"
  13. #include "portal_render_targets.h" //depth doubler
  14. #include "materialsystem/ITexture.h"
  15. #include "toolframework/itoolframework.h"
  16. #include "tier1/keyvalues.h"
  17. #include "view_scene.h"
  18. #include "viewrender.h"
  19. #include "shaderapi/ishaderapi.h"
  20. #include "vprof.h"
  21. #include "toolframework_client.h"
  22. #include "vgui_int.h"
  23. #include "renderparm.h"
  24. #ifdef PORTAL
  25. #include "c_prop_portal.h"
  26. #include "c_portal_player.h"
  27. #endif
  28. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecachePortalDrawingMaterials )
  29. PRECACHE( MATERIAL, "shadertest/wireframe" )
  30. PRECACHE( MATERIAL, "engine/writez_model" )
  31. PRECACHE( MATERIAL, "engine/TranslucentVertexColor" )
  32. PRECACHE_REGISTER_END()
  33. #define TEMP_DISABLE_PORTAL_VIS_QUERY
  34. static ConVar r_forcecheapwater( "r_forcecheapwater", "0", FCVAR_CLIENTDLL | FCVAR_CHEAT, "Force all water to be cheap water, will show old renders if enabled after water has been seen" );
  35. ConVar r_portal_stencil_depth( "r_portal_stencil_depth", "2", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "When using stencil views, this changes how many views within views we see" );
  36. ConVar r_portal_use_pvs_optimization( "r_portal_use_pvs_optimization", "1", 0, "Enables an optimization that allows portals to be culled when outside of the PVS." );
  37. ConVar r_portal_fastpath( "r_portal_fastpath", "1", 0 );
  38. ConVar r_portal_fastpath_max_ghost_recursion( "r_portal_fastpath_max_ghost_recursion", "2", 0 );
  39. ConVar r_portal_earlyz( "r_portal_earlyz", "1", 0 );
  40. ConVar r_portalscissor( "r_portalscissor", "0", 0 );
  41. extern ConVar portal_draw_ghosting;
  42. //-----------------------------------------------------------------------------
  43. //
  44. // Portal rendering management class
  45. //
  46. //-----------------------------------------------------------------------------
  47. static CPortalRender s_PortalRender;
  48. CPortalRender* g_pPortalRender = &s_PortalRender;
  49. //CUtlVector<PortalRenderableCreationFunction_t> CPortalRender::m_PortalRenderableCreators;
  50. CPortalRenderableCreator_AutoRegister *CPortalRenderableCreator_AutoRegister::s_pRegisteredTypes = NULL;
  51. //-------------------------------------------
  52. //Portal View ID Node helpers
  53. //-------------------------------------------
  54. PortalViewIDNode_t *AllocPortalViewIDNode( int iChildLinkCount, int nPortalIndex, int nTeam, int nParentID )
  55. {
  56. PortalViewIDNode_t *pNode = new PortalViewIDNode_t; //for now we just new/delete
  57. // Generate a new view ID that is completely unique based upon which portal we are, and who our parent is.
  58. // This only works for ~15 levels of recursion, after which, any other new IDs will alias with portals of previous levels because of overflow.
  59. // This should be ok, since we limit ourselves to 11 levels of recursion.
  60. if ( nParentID <= VIEW_ID_COUNT )
  61. {
  62. // If we're one of the standard view, we should be view 0
  63. Assert( nParentID == 0 );
  64. nParentID = 0; // parentID should be 0, but just in case slam it to 0
  65. }
  66. else
  67. {
  68. nParentID -= VIEW_ID_COUNT; // Bias and scale
  69. nParentID /= 2; // Collapse to remove skybox IDs
  70. }
  71. Assert( nTeam != 1 );
  72. nTeam %= 2; // Get team id into the 0..1 range. For single player the team id is 0... for multplayer it's 2 or 3 (TEAM_RED or TEAM_BLUE)
  73. // Figure out the index to the first child of our parentID.
  74. // Use a full quadtree numbering scheme. First child node starts at 1.
  75. int nFirstChild = nParentID * 4 + 1;
  76. int nPortalID = nTeam * 2 + nPortalIndex; // 0..3 range
  77. int nChildID = nFirstChild + nPortalID;
  78. nChildID *= 2; // Space them out so that viewID + 1 is the skybox view
  79. nChildID += VIEW_ID_COUNT; // Bias back into the VIEW_ID_COUNT range since we've reserved VIEW_ID_COUNT-1 view for primary viewIDs
  80. pNode->iPrimaryViewID = nChildID;
  81. CMatRenderContextPtr pRenderContext( materials );
  82. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  83. pNode->occlusionQueryHandle = pRenderContext->CreateOcclusionQueryObject();
  84. #endif
  85. pNode->iOcclusionQueryPixelsRendered = -5;
  86. pNode->iWindowPixelsAtQueryTime = 0;
  87. pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized = -1.0f;
  88. if( iChildLinkCount != 0 )
  89. {
  90. pNode->ChildNodes.SetCount( iChildLinkCount );
  91. memset( pNode->ChildNodes.Base(), NULL, sizeof( PortalViewIDNode_t * ) * iChildLinkCount );
  92. }
  93. return pNode;
  94. }
  95. void FreePortalViewIDNode( PortalViewIDNode_t *pNode )
  96. {
  97. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  98. {
  99. if( pNode->ChildNodes[i] != NULL )
  100. FreePortalViewIDNode( pNode->ChildNodes[i] );
  101. }
  102. CMatRenderContextPtr pRenderContext( materials );
  103. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  104. pRenderContext->DestroyOcclusionQueryObject( pNode->occlusionQueryHandle );
  105. #endif
  106. delete pNode; //for now we just new/delete
  107. }
  108. void IncreasePortalViewIDChildLinkCount( PortalViewIDNode_t *pNode )
  109. {
  110. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  111. {
  112. if( pNode->ChildNodes[i] != NULL )
  113. IncreasePortalViewIDChildLinkCount( pNode->ChildNodes[i] );
  114. }
  115. pNode->ChildNodes.AddToTail( NULL );
  116. }
  117. void RemovePortalViewIDChildLinkIndex( PortalViewIDNode_t *pNode, int iRemoveIndex )
  118. {
  119. Assert( pNode->ChildNodes.Count() > iRemoveIndex );
  120. if( pNode->ChildNodes[iRemoveIndex] != NULL )
  121. {
  122. FreePortalViewIDNode( pNode->ChildNodes[iRemoveIndex] );
  123. pNode->ChildNodes[iRemoveIndex] = NULL;
  124. }
  125. //I know the current behavior for CUtlVector::FastRemove() is to move the tail into the removed index. But I need that behavior to be true in the future as well so I'm doing it explicitly
  126. pNode->ChildNodes[iRemoveIndex] = pNode->ChildNodes.Tail();
  127. pNode->ChildNodes.Remove( pNode->ChildNodes.Count() - 1 );
  128. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  129. {
  130. if( pNode->ChildNodes[i] )
  131. RemovePortalViewIDChildLinkIndex( pNode->ChildNodes[i], iRemoveIndex );
  132. }
  133. }
  134. //-----------------------------------------------------------------------------
  135. //
  136. // Active Portal class
  137. //
  138. //-----------------------------------------------------------------------------
  139. CPortalRenderable::CPortalRenderable( void ) :
  140. m_bIsPlaybackPortal( false ),
  141. m_bIsPropPortal( false )
  142. {
  143. m_matrixThisToLinked.Identity();
  144. //Portal view ID indexing setup
  145. IncreasePortalViewIDChildLinkCount( &s_PortalRender.m_HeadPortalViewIDNode );
  146. m_iPortalViewIDNodeIndex = s_PortalRender.m_AllPortals.AddToTail( this );
  147. }
  148. CPortalRenderable::~CPortalRenderable( void )
  149. {
  150. int iLast = s_PortalRender.m_AllPortals.Count() - 1;
  151. //update the soon-to-be-transplanted portal's index
  152. s_PortalRender.m_AllPortals[iLast]->m_iPortalViewIDNodeIndex = m_iPortalViewIDNodeIndex;
  153. //I know the current behavior for CUtlVector::FastRemove() is to move the tail into the removed index. But I need that behavior to be true in the future as well so I'm doing it explicitly
  154. s_PortalRender.m_AllPortals[m_iPortalViewIDNodeIndex] = s_PortalRender.m_AllPortals.Tail();
  155. s_PortalRender.m_AllPortals.Remove( iLast );
  156. RemovePortalViewIDChildLinkIndex( &s_PortalRender.m_HeadPortalViewIDNode, m_iPortalViewIDNodeIndex ); //does the same transplant operation as above to all portal view id nodes
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Constructor
  160. //-----------------------------------------------------------------------------
  161. CPortalRender::CPortalRender()
  162. : m_MaterialsAccess( m_Materials )
  163. {
  164. m_iRemainingPortalViewDepth = 1; //let's portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
  165. m_iViewRecursionLevel = 0;
  166. m_pRenderingViewForPortal = NULL;
  167. m_pRenderingViewExitPortal = NULL;
  168. m_PortalViewIDNodeChain[0] = &m_HeadPortalViewIDNode;
  169. m_pCachedPortalQuadMeshData = NULL;
  170. }
  171. CPortalRender::~CPortalRender()
  172. {
  173. if ( m_pCachedPortalQuadMeshData )
  174. m_pCachedPortalQuadMeshData->Free();
  175. }
  176. void CPortalRender::LevelInitPreEntity()
  177. {
  178. // refresh materials - not sure if this needs to be done every level
  179. m_Materials.m_Wireframe.Init( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS );
  180. m_Materials.m_WriteZ_Model.Init( "engine/writez_model", TEXTURE_GROUP_CLIENT_EFFECTS );
  181. m_Materials.m_TranslucentVertexColor.Init( "engine/TranslucentVertexColor", TEXTURE_GROUP_CLIENT_EFFECTS );
  182. m_Materials.m_PortalDepthDoubler.Init( "models/portals/portal_depthdoubler", TEXTURE_GROUP_CLIENT_EFFECTS );
  183. m_Materials.m_nDepthDoubleViewMatrixVarCache = 0;
  184. m_Materials.m_PortalDepthDoubler->FindVarFast( "$alternateviewmatrix", &m_Materials.m_nDepthDoubleViewMatrixVarCache ); // Warm cache
  185. }
  186. void CPortalRender::LevelShutdownPreEntity()
  187. {
  188. int nCount = m_RecordedPortals.Count();
  189. for ( int i = 0; i < nCount; ++i )
  190. {
  191. delete m_RecordedPortals[i].m_pActivePortal;
  192. }
  193. m_RecordedPortals.RemoveAll();
  194. }
  195. int CPortalRender::ShouldForceCheaperWaterLevel() const
  196. {
  197. if( r_forcecheapwater.GetBool() )
  198. return 0;
  199. if ( IsGameConsole() )
  200. {
  201. // Force cheap water in portals more than 1 deep
  202. // and altogether in co-op
  203. // if ( m_iViewRecursionLevel > 1 || GameRules()->IsMultiplayer() )
  204. if ( m_iViewRecursionLevel > 1 )
  205. {
  206. return 0;
  207. }
  208. else
  209. {
  210. return 3;
  211. }
  212. }
  213. if( m_iViewRecursionLevel > 0 )
  214. {
  215. if( m_iViewRecursionLevel > 2 )
  216. return 0;
  217. PortalViewIDNode_t *pPixelVisNode = m_PortalViewIDNodeChain[m_iViewRecursionLevel - 1]->ChildNodes[m_pRenderingViewForPortal->m_iPortalViewIDNodeIndex];
  218. if( pPixelVisNode->fScreenFilledByPortalSurfaceLastFrame_Normalized >= 0.0f )
  219. {
  220. if( pPixelVisNode->fScreenFilledByPortalSurfaceLastFrame_Normalized < 0.005f )
  221. return 0;
  222. if( pPixelVisNode->fScreenFilledByPortalSurfaceLastFrame_Normalized < 0.02f )
  223. return 1;
  224. if( pPixelVisNode->fScreenFilledByPortalSurfaceLastFrame_Normalized < 0.05f )
  225. return 2;
  226. }
  227. }
  228. return 3;
  229. }
  230. bool CPortalRender::ShouldObeyStencilForClears() const
  231. {
  232. return (m_iViewRecursionLevel > 0);
  233. }
  234. void CPortalRender::WaterRenderingHandler_PreReflection() const
  235. {
  236. if( m_iViewRecursionLevel > 0 )
  237. {
  238. CMatRenderContextPtr pRenderContext( materials );
  239. ShaderStencilState_t tempState = m_StencilState;
  240. tempState.m_bEnable = false;
  241. pRenderContext->SetStencilState( tempState );
  242. }
  243. }
  244. void CPortalRender::WaterRenderingHandler_PostReflection() const
  245. {
  246. if( m_iViewRecursionLevel > 0 )
  247. {
  248. CMatRenderContextPtr pRenderContext( materials );
  249. ShaderStencilState_t tempState = m_StencilState;
  250. tempState.m_bEnable = true;
  251. pRenderContext->SetStencilState( tempState );
  252. }
  253. }
  254. void CPortalRender::WaterRenderingHandler_PreRefraction() const
  255. {
  256. if( m_iViewRecursionLevel > 0 )
  257. {
  258. CMatRenderContextPtr pRenderContext( materials );
  259. ShaderStencilState_t tempState = m_StencilState;
  260. tempState.m_bEnable = false;
  261. pRenderContext->SetStencilState( tempState );
  262. }
  263. }
  264. void CPortalRender::WaterRenderingHandler_PostRefraction() const
  265. {
  266. if( m_iViewRecursionLevel > 0 )
  267. {
  268. CMatRenderContextPtr pRenderContext( materials );
  269. ShaderStencilState_t tempState = m_StencilState;
  270. tempState.m_bEnable = true;
  271. pRenderContext->SetStencilState( tempState );
  272. }
  273. }
  274. void Recursive_UpdatePortalPixelVisibility( PortalViewIDNode_t *pNode, IMatRenderContext *pRenderContext )
  275. {
  276. if( pNode->iWindowPixelsAtQueryTime > 0 )
  277. {
  278. if( pNode->iOcclusionQueryPixelsRendered < -1 )
  279. {
  280. //First couple queries. We seem to be getting bogus 0's on the first queries sometimes. ignore the results.
  281. ++pNode->iOcclusionQueryPixelsRendered;
  282. pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized = -1.0f;
  283. }
  284. else
  285. {
  286. pNode->iOcclusionQueryPixelsRendered = pRenderContext->OcclusionQuery_GetNumPixelsRendered( pNode->occlusionQueryHandle );
  287. pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized = ((float)pNode->iOcclusionQueryPixelsRendered) / ((float)pNode->iWindowPixelsAtQueryTime);
  288. }
  289. }
  290. else
  291. {
  292. pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized = -1.0f;
  293. }
  294. pNode->iWindowPixelsAtQueryTime = 0;
  295. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  296. {
  297. PortalViewIDNode_t *pChildNode = pNode->ChildNodes[i];
  298. if( pChildNode )
  299. Recursive_UpdatePortalPixelVisibility( pChildNode, pRenderContext );
  300. }
  301. }
  302. void CPortalRender::UpdatePortalPixelVisibility( void )
  303. {
  304. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  305. return;
  306. #endif
  307. if( m_iViewRecursionLevel != 0 )
  308. return;
  309. IMatRenderContext *pRenderContext = materials->GetRenderContext();
  310. //CMatRenderContextPtr pRenderContext( materials );
  311. for( int i = m_HeadPortalViewIDNode.ChildNodes.Count(); --i >= 0; )
  312. {
  313. PortalViewIDNode_t *pChildNode = m_HeadPortalViewIDNode.ChildNodes[i];
  314. if( pChildNode )
  315. Recursive_UpdatePortalPixelVisibility( pChildNode, pRenderContext );
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Invalidates pixel visibility data for all portals for this next frame.
  320. //-----------------------------------------------------------------------------
  321. void Recursive_InvalidatePortalPixelVis( PortalViewIDNode_t *pNode )
  322. {
  323. pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized = -1.0f;
  324. pNode->iOcclusionQueryPixelsRendered = -5;
  325. pNode->iWindowPixelsAtQueryTime = 0;
  326. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  327. {
  328. PortalViewIDNode_t *pChildNode = pNode->ChildNodes[i];
  329. if( pChildNode )
  330. Recursive_InvalidatePortalPixelVis( pChildNode );
  331. }
  332. }
  333. ConVar cl_useOldSwapPortalVisibilityCode( "cl_useoldswapportalvisibilitycode", "0" );
  334. //-----------------------------------------------------------------------------
  335. // Purpose: Preserves pixel visibility data when view id's are getting swapped around
  336. //-----------------------------------------------------------------------------
  337. void CPortalRender::EnteredPortal( int nPlayerSlot, CPortalRenderable *pEnteredPortal )
  338. {
  339. CPortalRenderable *pExitPortal = pEnteredPortal->GetLinkedPortal();
  340. Assert( pExitPortal != NULL );
  341. if ( pExitPortal == NULL )
  342. return;
  343. if ( cl_useOldSwapPortalVisibilityCode.GetInt() )
  344. {
  345. // The following code doesn't seem to function as intended. It adds an extra portal view id to the head of the exit portal's head and tries to transfer the visibility from
  346. // the main views to it. Then it tries to transfer the visibility from the entered portal view to the main view. Unfortunately, this still doesn't give us valid
  347. // visibility queries and we get query popping when passing through a portal and is overly complicated. It also messes up the the nicely ordered viewIDs that reduce query results popping
  348. // when view ids change (due to a new portal coming into view).
  349. int iNodeLinkCount = m_HeadPortalViewIDNode.ChildNodes.Count();
  350. PortalViewIDNode_t *pNewHead = m_HeadPortalViewIDNode.ChildNodes[pEnteredPortal->m_iPortalViewIDNodeIndex];
  351. m_HeadPortalViewIDNode.ChildNodes[pEnteredPortal->m_iPortalViewIDNodeIndex] = NULL;
  352. //Create a new node that will preserve main's visibility. This new node will be linked to the new head node at the exit portal's index (imagine entering a portal walking backwards)
  353. C_Prop_Portal *pPropPortal = static_cast<C_Prop_Portal*>( pExitPortal );
  354. int nPortalIndex = pPropPortal->m_bIsPortal2 ? 1 : 0;
  355. int nTeamIndex = pPropPortal->GetTeamNumber();
  356. PortalViewIDNode_t *pExitPortalsNewNode = AllocPortalViewIDNode( iNodeLinkCount, nPortalIndex, nTeamIndex, VIEW_MAIN );
  357. {
  358. for( int i = 0; i != iNodeLinkCount; ++i )
  359. {
  360. pExitPortalsNewNode->ChildNodes[i] = m_HeadPortalViewIDNode.ChildNodes[i];
  361. m_HeadPortalViewIDNode.ChildNodes[i] = NULL;
  362. }
  363. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, VIEW_MAIN, pExitPortalsNewNode->iPrimaryViewID );
  364. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, VIEW_3DSKY, pExitPortalsNewNode->iPrimaryViewID + 1 );
  365. }
  366. if( pNewHead ) //it's possible we entered a portal we couldn't see through
  367. {
  368. Assert( pNewHead->ChildNodes.Count() == m_HeadPortalViewIDNode.ChildNodes.Count() );
  369. Assert( pNewHead->ChildNodes[pExitPortal->m_iPortalViewIDNodeIndex] == NULL ); //seeing out of an exit portal back into itself should be impossible
  370. for( int i = 0; i != iNodeLinkCount; ++i )
  371. {
  372. m_HeadPortalViewIDNode.ChildNodes[i] = pNewHead->ChildNodes[i];
  373. pNewHead->ChildNodes[i] = NULL; //going to be freeing the node in a minute, don't want to kill transplanted children
  374. }
  375. //Since the primary views will always be 0 and 1, we have to shift results instead of replacing the id's
  376. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, pNewHead->iPrimaryViewID, VIEW_MAIN );
  377. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, pNewHead->iPrimaryViewID + 1, VIEW_3DSKY );
  378. FreePortalViewIDNode( pNewHead );
  379. }
  380. Assert( m_HeadPortalViewIDNode.ChildNodes[pExitPortal->m_iPortalViewIDNodeIndex] == NULL ); //asserted above in pNewHead code, but call me paranoid
  381. m_HeadPortalViewIDNode.ChildNodes[pExitPortal->m_iPortalViewIDNodeIndex] = pExitPortalsNewNode;
  382. }
  383. else
  384. {
  385. // This code is much simpler, does essentially the same thing as the code above, and doesn't have to create a new view.
  386. // It still causes some popping, but doesn't create a new view or ID.
  387. PortalViewIDNode_t *pEnteredView = m_HeadPortalViewIDNode.ChildNodes[ pEnteredPortal->m_iPortalViewIDNodeIndex ];
  388. if ( pEnteredView )
  389. {
  390. C_Prop_Portal *pPropPortal = static_cast<C_Prop_Portal*>( pExitPortal );
  391. int nToExitPortal = pPropPortal->m_bIsPortal2 ? 2 : -2;
  392. int nExitPortalID = pEnteredView->iPrimaryViewID + nToExitPortal;
  393. // Shift queries from the main view to the exit portal view... which is just 2 more or less than the current portal view
  394. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, VIEW_MAIN, nExitPortalID );
  395. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, VIEW_3DSKY, nExitPortalID + 1 );
  396. // Shift visibility from the entered view to the main view
  397. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, pEnteredView->iPrimaryViewID, VIEW_MAIN );
  398. PixelVisibility_ShiftVisibilityViews( nPlayerSlot, pEnteredView->iPrimaryViewID + 1, VIEW_3DSKY );
  399. }
  400. }
  401. //Because pixel visibility is based off of *last* frame's visibility. We can get cases where a certain portal
  402. //wasn't visible last frame, but is takes up most of the screen this frame.
  403. //Set all portal pixel visibility to unknown visibility.
  404. for( int i = m_HeadPortalViewIDNode.ChildNodes.Count(); --i >= 0; )
  405. {
  406. PortalViewIDNode_t *pChildNode = m_HeadPortalViewIDNode.ChildNodes[i];
  407. if( pChildNode )
  408. Recursive_InvalidatePortalPixelVis( pChildNode );
  409. }
  410. }
  411. static inline int ComputeStencilRefValue( int nViewRecursionLevel, int nPortalIdx, int nParentPortalIdx )
  412. {
  413. Assert( nViewRecursionLevel < 2 );
  414. if ( nViewRecursionLevel > 0 )
  415. {
  416. return ( ( ( 1 << nPortalIdx ) & 0xF ) << 4 ) | ( ( 1 << nParentPortalIdx ) & 0xF );
  417. }
  418. return ( 1 << nPortalIdx ) & 0xF;
  419. }
  420. static inline int ComputeStencilRestoreTestMask( int nViewRecursionLevel, int nPortalIdx )
  421. {
  422. Assert( nViewRecursionLevel < 2 );
  423. return ( ( 1 << nPortalIdx ) & 0xF ) << ( nViewRecursionLevel * 4 );
  424. }
  425. ConVar r_portalstencildisable( "r_portalstencildisable", "0" );
  426. //-----------------------------------------------------------------------------------------------------------------------------------
  427. void CPortalRender::DrawPortalGhostLocations( IMatRenderContext *pRenderContext, IMesh *pPortalQuadMesh, const GhostPortalRenderInfo_t *pGhostPortalRenderInfos, int nPortalCount ) const
  428. {
  429. VPROF_BUDGET( "PortalGhosts", "PortalGhosts" );
  430. if( !ToolsEnabled() &&
  431. portal_draw_ghosting.GetBool() &&
  432. ( r_portal_fastpath_max_ghost_recursion.GetInt() > m_iViewRecursionLevel ) )
  433. {
  434. if ( nPortalCount == 0 )
  435. {
  436. return;
  437. }
  438. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal Ghosts" );
  439. const CPortalRenderable *pExitView = GetCurrentViewExitPortal();
  440. pRenderContext->MatrixMode( MATERIAL_MODEL ); //just in case
  441. pRenderContext->PushMatrix();
  442. pRenderContext->LoadIdentity();
  443. for ( int i = 0; i < nPortalCount; i++ )
  444. {
  445. if ( pGhostPortalRenderInfos[i].m_pPortal == pExitView )
  446. {
  447. continue;
  448. }
  449. pRenderContext->Bind( pGhostPortalRenderInfos[i].m_pGhostMaterial, pGhostPortalRenderInfos[i].m_pPortal->GetClientRenderable() );
  450. pPortalQuadMesh->Draw( pGhostPortalRenderInfos[i].m_nGhostPortalQuadIndex * 6, 6 );
  451. }
  452. pRenderContext->MatrixMode( MATERIAL_MODEL );
  453. pRenderContext->PopMatrix();
  454. pRenderContext->EndPIXEvent();
  455. }
  456. }
  457. #ifdef _PS3
  458. void CPortalRender::ReloadZcullMemory()
  459. {
  460. CMatRenderContextPtr pRenderContext( materials );
  461. pRenderContext->ReloadZcullMemory( m_StencilState.m_nReferenceValue );
  462. int nOldWriteMask = m_StencilState.m_nWriteMask;
  463. m_StencilState.m_nWriteMask = 0;
  464. pRenderContext->SetStencilState( m_StencilState );
  465. m_StencilState.m_nWriteMask = nOldWriteMask;
  466. }
  467. #endif // _PS3
  468. void CPortalRender::DrawEarlyZPortals( CViewRender *pViewRender )
  469. {
  470. VPROF_BUDGET( "CPortalRender::DrawEarlyZPortals", "DrawEarlyZPortals" );
  471. if ( !r_portal_earlyz.GetBool() || !r_portal_fastpath.GetBool() || ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED ) )
  472. {
  473. return;
  474. }
  475. int iDrawFlags = pViewRender->GetDrawFlags();
  476. if ( (iDrawFlags & DF_RENDER_REFLECTION) != 0 )
  477. return;
  478. if ( ((iDrawFlags & DF_CLIP_Z) != 0) && ((iDrawFlags & DF_CLIP_BELOW) == 0) ) //clipping above the water height
  479. return;
  480. CMatRenderContextPtr pRenderContext( materials );
  481. int iNumRenderablePortals = m_ActivePortals.Count();
  482. if ( iNumRenderablePortals == 0 )
  483. {
  484. return;
  485. }
  486. if ( m_iViewRecursionLevel > 0 )
  487. {
  488. return;
  489. }
  490. IMesh *pPortalQuadMesh = NULL;
  491. // Make a vertex buffer with all portal quads
  492. if ( m_pCachedPortalQuadMeshData ) // Free it from the last time
  493. {
  494. m_pCachedPortalQuadMeshData->Free();
  495. }
  496. m_pCachedPortalQuadMeshData = NULL;
  497. pPortalQuadMesh = CPortalRenderable_FlatBasic::CreateMeshForPortals( pRenderContext, m_ActivePortals.Count(), m_ActivePortals.Base(), m_clampedPortalMeshRenderInfos );
  498. m_portalIsOpening.SetCount( iNumRenderablePortals );
  499. for ( int i = 0; i < m_portalIsOpening.Count(); i++ )
  500. {
  501. m_portalIsOpening[i] = m_ActivePortals[i]->IsPropPortal() && static_cast<C_Prop_Portal *>( m_ActivePortals[i] )->IsPortalOpening();
  502. }
  503. CUtlVector< CPortalRenderable* > actualActivePortals( 0, iNumRenderablePortals );
  504. CUtlVector< int > actualActivePortalQuadVBIndex( 0, iNumRenderablePortals );
  505. if ( true ) //( ToolsEnabled() )
  506. {
  507. // This loop is necessary because tools can suppress rendering without telling the portal system
  508. for ( int i = 0; i < iNumRenderablePortals; ++i )
  509. {
  510. CPortalRenderable *pPortalRenderable = m_ActivePortals[i];
  511. C_BaseEntity *pPairedEntity = pPortalRenderable->PortalRenderable_GetPairedEntity();
  512. bool bIsVisible = (pPairedEntity == NULL) || (pPairedEntity->IsVisible() && pPairedEntity->ShouldDraw()); //either unknown visibility or definitely visible.
  513. // If the portal is associated with an entity, check to see if that entity is even in the PVS before rendering the portal
  514. if ( pPairedEntity != NULL && r_portal_use_pvs_optimization.GetBool() )
  515. {
  516. IClientRenderable *pCR = pPairedEntity->GetClientRenderable();
  517. bool bIsRenderable = g_pClientLeafSystem->IsRenderableInPVS( pCR );
  518. bIsVisible &= bIsRenderable;
  519. }
  520. if ( !pPortalRenderable->m_bIsPlaybackPortal )
  521. {
  522. if ( !bIsVisible )
  523. {
  524. //can't see through the portal, free up it's view id node for use elsewhere
  525. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] != NULL )
  526. {
  527. FreePortalViewIDNode( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] );
  528. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] = NULL;
  529. }
  530. continue;
  531. }
  532. }
  533. if ( m_portalIsOpening[i] )
  534. {
  535. // Don't draw, otherwise the refract effect will have no pixels to pull from
  536. continue;
  537. }
  538. actualActivePortals.AddToTail( m_ActivePortals[i] );
  539. actualActivePortalQuadVBIndex.AddToTail( i );
  540. }
  541. }
  542. else
  543. {
  544. // Waste some time on the consoles to make the code below work the same
  545. actualActivePortals.AddVectorToTail( m_ActivePortals );
  546. for ( int i = 0; i < iNumRenderablePortals; i++ )
  547. {
  548. actualActivePortalQuadVBIndex.AddToTail( i );
  549. }
  550. }
  551. iNumRenderablePortals = actualActivePortals.Count();
  552. if( iNumRenderablePortals == 0 )
  553. {
  554. if ( pPortalQuadMesh )
  555. {
  556. pPortalQuadMesh->MarkAsDrawn();
  557. }
  558. return;
  559. }
  560. if( m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].Count() == 0 )
  561. {
  562. //nothing in the complex frustum from the current view, copy the standard frustum in
  563. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].AddMultipleToTail( FRUSTUM_NUMPLANES, pViewRender->GetFrustum() );
  564. }
  565. //step 1, write out the stencil values (and colors if you want, but really not necessary)
  566. {
  567. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_EarlyZ" );
  568. for ( int i = 0; i < actualActivePortals.Count(); i++ )
  569. {
  570. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  571. IMaterial *pMat = pCurrentPortal->IsPropPortal() ? C_Prop_Portal::m_Materials.m_Portal_Stencil_Hole : C_Portal_Base2D::m_Materials.m_Portal_Stencil_Hole;
  572. pRenderContext->Bind( pMat, assert_cast< CPortalRenderable_FlatBasic* >( pCurrentPortal )->GetClientRenderable() );
  573. int nStartIndex = actualActivePortalQuadVBIndex[i] * 6;
  574. int nIndexCount = 6;
  575. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  576. if ( ( m_iViewRecursionLevel == 0 ) && ( m_clampedPortalMeshRenderInfos[ actualActivePortalQuadVBIndex[i] ].nStartIndex >= 0 ) )
  577. {
  578. // Draw near plane cap
  579. nStartIndex = m_clampedPortalMeshRenderInfos[ actualActivePortalQuadVBIndex[i] ].nStartIndex;
  580. nIndexCount = m_clampedPortalMeshRenderInfos[ actualActivePortalQuadVBIndex[i] ].nIndexCount;
  581. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  582. }
  583. }
  584. pRenderContext->EndPIXEvent();
  585. }
  586. if ( pPortalQuadMesh )
  587. {
  588. pPortalQuadMesh->MarkAsDrawn();
  589. }
  590. }
  591. //-----------------------------------------------------------------------------------------------------------------------------------
  592. //-----------------------------------------------------------------------------------------------------------------------------------
  593. //-----------------------------------------------------------------------------------------------------------------------------------
  594. //-----------------------------------------------------------------------------------------------------------------------------------
  595. //-----------------------------------------------------------------------------------------------------------------------------------
  596. //-----------------------------------------------------------------------------------------------------------------------------------
  597. bool CPortalRender::DrawPortalsUsingStencils( CViewRender *pViewRender )
  598. {
  599. VPROF_BUDGET( "CPortalRender::DrawPortalsUsingStencils", "DrawPortalsUsingStencils" );
  600. if ( !r_portal_fastpath.GetBool() ||
  601. ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED ) ) // only QMS supports the VB restores I'm doing right now
  602. {
  603. return DrawPortalsUsingStencils_Old( pViewRender );
  604. }
  605. int iDrawFlags = pViewRender->GetDrawFlags();
  606. if ( (iDrawFlags & DF_RENDER_REFLECTION) != 0 )
  607. return false;
  608. if ( ((iDrawFlags & DF_CLIP_Z) != 0) && ((iDrawFlags & DF_CLIP_BELOW) == 0) ) //clipping above the water height
  609. return false;
  610. if ( m_AllPortals.Count() == 0 )
  611. {
  612. return false;
  613. }
  614. CMatRenderContextPtr pRenderContext( materials );
  615. IMesh *pPortalQuadMesh = NULL;
  616. if ( m_iViewRecursionLevel == 0 )
  617. {
  618. m_portalGhostRenderInfos.RemoveAll();
  619. C_Prop_Portal::BuildPortalGhostRenderInfo( m_AllPortals, m_portalGhostRenderInfos );
  620. }
  621. // Make a vertex buffer with all portal quads
  622. if ( m_iViewRecursionLevel == 0 )
  623. {
  624. if ( m_pCachedPortalQuadMeshData ) // Free it from the last time
  625. {
  626. m_pCachedPortalQuadMeshData->Free();
  627. }
  628. m_pCachedPortalQuadMeshData = NULL;
  629. pPortalQuadMesh = CPortalRenderable_FlatBasic::CreateMeshForPortals( pRenderContext, m_AllPortals.Count(), m_AllPortals.Base(), m_clampedPortalMeshRenderInfos );
  630. m_pCachedPortalQuadMeshData = pPortalQuadMesh->GetCachedPerFrameMeshData();
  631. Assert( m_pCachedPortalQuadMeshData );
  632. m_portalQuadMeshVertexFmt = pPortalQuadMesh->GetVertexFormat();
  633. m_portalIsOpening.SetCount( m_AllPortals.Count() );
  634. for ( int i = 0; i < m_portalIsOpening.Count(); i++ )
  635. {
  636. m_portalIsOpening[i] = m_AllPortals[i]->IsPropPortal() && static_cast<C_Prop_Portal *>( m_AllPortals[i] )->IsPortalOpening();
  637. }
  638. }
  639. #ifdef PORTAL
  640. {
  641. if ( pPortalQuadMesh == NULL )
  642. {
  643. Assert( m_pCachedPortalQuadMeshData );
  644. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  645. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  646. }
  647. DrawPortalGhostLocations( pRenderContext, pPortalQuadMesh, m_portalGhostRenderInfos.Base(), m_portalGhostRenderInfos.Count() );
  648. }
  649. #endif
  650. if ( m_ActivePortals.Count() == 0 )
  651. {
  652. if ( pPortalQuadMesh )
  653. {
  654. pPortalQuadMesh->MarkAsDrawn();
  655. }
  656. return false;
  657. }
  658. CUtlVector< CPortalRenderable* > actualActivePortals( 0, m_ActivePortals.Count() );
  659. CUtlVector< int > actualActivePortalQuadVBIndex( 0, m_ActivePortals.Count() );
  660. {
  661. // This loop is necessary because tools can suppress rendering without telling the portal system
  662. for ( int i = 0; i < m_ActivePortals.Count(); ++i )
  663. {
  664. CPortalRenderable *pPortalRenderable = m_ActivePortals[i];
  665. C_BaseEntity *pPairedEntity = pPortalRenderable->PortalRenderable_GetPairedEntity();
  666. bool bIsVisible = (pPairedEntity == NULL) || (pPairedEntity->IsVisible() && pPairedEntity->ShouldDraw()); //either unknown visibility or definitely visible.
  667. // If the portal is associated with an entity, check to see if that entity is even in the PVS before rendering the portal
  668. if ( pPairedEntity != NULL && r_portal_use_pvs_optimization.GetBool() )
  669. {
  670. IClientRenderable *pCR = pPairedEntity->GetClientRenderable();
  671. bool bIsRenderable = g_pClientLeafSystem->IsRenderableInPVS( pCR );
  672. bIsVisible &= bIsRenderable;
  673. }
  674. if ( !pPortalRenderable->m_bIsPlaybackPortal )
  675. {
  676. if ( !bIsVisible )
  677. {
  678. //can't see through the portal, free up it's view id node for use elsewhere
  679. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] != NULL )
  680. {
  681. FreePortalViewIDNode( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] );
  682. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] = NULL;
  683. }
  684. continue;
  685. }
  686. }
  687. actualActivePortals.AddToTail( m_ActivePortals[i] );
  688. actualActivePortalQuadVBIndex.AddToTail( m_ActivePortals[i]->m_iPortalViewIDNodeIndex );
  689. }
  690. }
  691. if( actualActivePortals.Count() == 0 )
  692. {
  693. if ( pPortalQuadMesh )
  694. {
  695. pPortalQuadMesh->MarkAsDrawn();
  696. }
  697. return false;
  698. }
  699. const int iMaxDepth = MIN( r_portal_stencil_depth.GetInt(), MIN( MAX_PORTAL_RECURSIVE_VIEWS, (1 << materials->StencilBufferBits() ) ) - 1 );
  700. if ( pPortalQuadMesh == NULL )
  701. {
  702. Assert( m_pCachedPortalQuadMeshData );
  703. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  704. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  705. }
  706. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_PORTAL_RECURSION_DEPTH, m_iViewRecursionLevel );
  707. if( m_iViewRecursionLevel >= iMaxDepth ) //can't support any more views
  708. {
  709. if ( m_stencilValueStack.Count() > 0 )
  710. {
  711. int nDummy;
  712. m_stencilValueStack.Pop( nDummy );
  713. }
  714. if ( m_parentPortalIdStack.Count() > 0 )
  715. {
  716. int nDummy;
  717. m_parentPortalIdStack.Pop( nDummy );
  718. }
  719. m_iRemainingPortalViewDepth = 0; //special case handler for max depth 0 cases
  720. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_maxrecursion_reached" );
  721. RenderPortalEffects( pRenderContext, pPortalQuadMesh, actualActivePortals, actualActivePortalQuadVBIndex );
  722. pRenderContext->EndPIXEvent();
  723. if ( pPortalQuadMesh )
  724. {
  725. pPortalQuadMesh->MarkAsDrawn();
  726. }
  727. return false;
  728. }
  729. m_iRemainingPortalViewDepth = (iMaxDepth - m_iViewRecursionLevel) - 1;
  730. pRenderContext->Flush( true ); //to prevent screwing up the last opaque object
  731. const CViewSetup *pViewSetup = pViewRender->GetViewSetup();
  732. m_RecursiveViewSetups[m_iViewRecursionLevel] = *pViewSetup;
  733. CViewSetup ViewBackup;// = *pViewSetup; //backup the view, we'll need to restore it
  734. memcpy( &ViewBackup, pViewSetup, sizeof( CViewSetup ) );
  735. Vector ptCameraOrigin = pViewSetup->origin;
  736. Vector vCameraForward;
  737. AngleVectors( pViewSetup->angles, &vCameraForward, NULL, NULL );
  738. int iX, iY, iWidth, iHeight;
  739. pRenderContext->GetViewport( iX, iY, iWidth, iHeight );
  740. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  741. int iScreenPixelCount = iWidth * iHeight;
  742. #endif
  743. bool bRebuildDrawListsWhenDone = false;
  744. int iParentLevelStencilReferenceValue = m_iViewRecursionLevel;
  745. if( m_iViewRecursionLevel == 0 ) //first entry into the stencil drawing
  746. {
  747. m_StencilState.m_bEnable = true;
  748. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  749. m_StencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  750. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  751. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  752. m_StencilState.m_nTestMask = 0xFF;
  753. m_StencilState.m_nWriteMask = 0xFF;
  754. m_StencilState.m_nReferenceValue = 0;
  755. pRenderContext->SetStencilState( m_StencilState );
  756. pRenderContext->PerformFullScreenStencilOperation(); // Clear stencil. Is this really necessary?
  757. pPortalQuadMesh = NULL; // NULL it out so we know to restore our dynamic mesh later
  758. m_RecursiveViewComplexFrustums[0].RemoveAll(); //clear any garbage leftover in the complex frustums from last frame
  759. // Properly prime our stacks of stuff
  760. m_stencilValueStack.Push( m_StencilState.m_nReferenceValue );
  761. m_parentPortalIdStack.Push( -1 );
  762. }
  763. if( m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].Count() == 0 )
  764. {
  765. //nothing in the complex frustum from the current view, copy the standard frustum in
  766. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].AddMultipleToTail( FRUSTUM_NUMPLANES, pViewRender->GetFrustum() );
  767. }
  768. CUtlVector< CPortalRenderable* > portalRenderablesToDraw( 0, actualActivePortals.Count() );
  769. CUtlVector< int > portalsRenderablesToDrawVBIndex( 0, actualActivePortals.Count() );
  770. for( int i = 0; i < actualActivePortals.Count(); ++i )
  771. {
  772. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  773. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel + 1].RemoveAll(); //clear any previously stored complex frustum
  774. if( (pCurrentPortal->GetLinkedPortal() == NULL) ||
  775. (pCurrentPortal == m_pRenderingViewExitPortal) ||
  776. (pCurrentPortal->ShouldUpdatePortalView_BasedOnView( *pViewSetup, m_RecursiveViewComplexFrustums[m_iViewRecursionLevel] ) == false) )
  777. {
  778. //can't see through the portal, free up it's view id node for use elsewhere
  779. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] != NULL )
  780. {
  781. FreePortalViewIDNode( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] );
  782. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] = NULL;
  783. }
  784. continue;
  785. }
  786. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes.Count() > pCurrentPortal->m_iPortalViewIDNodeIndex );
  787. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] == NULL )
  788. {
  789. C_Prop_Portal *pPropPortal = static_cast<C_Prop_Portal*>( pCurrentPortal );
  790. int nPortalIndex = pPropPortal->m_bIsPortal2 ? 1 : 0;
  791. int nTeamIndex = pPropPortal->GetTeamNumber();
  792. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] = AllocPortalViewIDNode( m_HeadPortalViewIDNode.ChildNodes.Count(), nPortalIndex, nTeamIndex, CurrentViewID() );
  793. }
  794. // PortalViewIDNode_t *pCurrentPortalViewNode = m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex];
  795. portalRenderablesToDraw.AddToTail( pCurrentPortal );
  796. portalsRenderablesToDrawVBIndex.AddToTail( actualActivePortalQuadVBIndex[ i ] );
  797. }
  798. if ( portalRenderablesToDraw.Count() > 4 )
  799. {
  800. Warning( "More than 4 visible portals (recursion level %d)\n", m_iViewRecursionLevel );
  801. }
  802. // Step 0, Allow for special effects to happen before cutting a hole
  803. {
  804. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step0_prestencil_effects" );
  805. m_StencilState.m_bEnable = true;
  806. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  807. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  808. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  809. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  810. m_StencilState.m_nTestMask = 0xFF;
  811. m_StencilState.m_nWriteMask = 0xFF;
  812. m_StencilState.m_nReferenceValue = iParentLevelStencilReferenceValue; // FIXME
  813. pRenderContext->SetStencilState( m_StencilState );
  814. if ( pPortalQuadMesh == NULL )
  815. {
  816. Assert( m_pCachedPortalQuadMeshData );
  817. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  818. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  819. }
  820. for ( int i = 0; i < portalRenderablesToDraw.Count(); i++ )
  821. {
  822. bool bRefractTextureInitialized = false;
  823. if ( m_portalIsOpening[ portalsRenderablesToDrawVBIndex[i] ] )
  824. {
  825. CPortalRenderable *pCurrentPortal = portalRenderablesToDraw[i];
  826. //pCurrentPortal->DrawPreStencilMask( pRenderContext );
  827. pRenderContext->Bind( C_Prop_Portal::m_Materials.m_Portal_Refract, assert_cast< CPortalRenderable_FlatBasic* >( pCurrentPortal )->GetClientRenderable() );
  828. if ( !bRefractTextureInitialized )
  829. {
  830. // This can depend on the Bind command above, so keep this after!
  831. UpdateFrontBufferTexturesForMaterial( C_Prop_Portal::m_Materials.m_Portal_Refract );
  832. bRefractTextureInitialized = true;
  833. }
  834. int nStartIndex = portalsRenderablesToDrawVBIndex[i] * 6;
  835. int nIndexCount = 6;
  836. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  837. }
  838. }
  839. pRenderContext->EndPIXEvent();
  840. }
  841. int nParentPortalIdx = -1;
  842. m_parentPortalIdStack.Pop( nParentPortalIdx );
  843. //step 1, write out the stencil values (and colors if you want, but really not necessary)
  844. {
  845. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step1_writestencil" );
  846. if ( m_iViewRecursionLevel == 0 )
  847. {
  848. m_StencilState.m_bEnable = true;
  849. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  850. m_StencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  851. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  852. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  853. m_StencilState.m_nTestMask = 0xFF;
  854. m_StencilState.m_nWriteMask = 0xFF;
  855. }
  856. else
  857. {
  858. Assert( m_iViewRecursionLevel == 1 ); // We only support two-level recursion
  859. m_StencilState.m_bEnable = true;
  860. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  861. m_StencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  862. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  863. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  864. m_StencilState.m_nTestMask = 0x0F;
  865. m_StencilState.m_nWriteMask = 0xF0;
  866. }
  867. if ( pPortalQuadMesh == NULL )
  868. {
  869. Assert( m_pCachedPortalQuadMeshData );
  870. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  871. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  872. }
  873. for ( int i = 0; i < portalRenderablesToDraw.Count(); i++ )
  874. {
  875. CPortalRenderable *pCurrentPortal = portalRenderablesToDraw[i];
  876. m_StencilState.m_nReferenceValue = ComputeStencilRefValue( m_iViewRecursionLevel, i, nParentPortalIdx );
  877. pRenderContext->SetStencilState( m_StencilState );
  878. IMaterial *pMat = pCurrentPortal->IsPropPortal() ? C_Prop_Portal::m_Materials.m_Portal_Stencil_Hole : C_Portal_Base2D::m_Materials.m_Portal_Stencil_Hole;
  879. pRenderContext->Bind( pMat, assert_cast< CPortalRenderable_FlatBasic* >( pCurrentPortal )->GetClientRenderable() );
  880. int nStartIndex = portalsRenderablesToDrawVBIndex[i] * 6;
  881. int nIndexCount = 6;
  882. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  883. if ( ( m_iViewRecursionLevel == 0 ) && ( m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nStartIndex >= 0 ) )
  884. {
  885. // Draw near plane cap
  886. nStartIndex = m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nStartIndex;
  887. nIndexCount = m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nIndexCount;
  888. pRenderContext->OverrideDepthEnable( true, true, false );
  889. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  890. pRenderContext->OverrideDepthEnable( false, true, true );
  891. }
  892. }
  893. pRenderContext->EndPIXEvent();
  894. }
  895. // Compute inverse view-projection matrix
  896. VMatrix matView;
  897. VMatrix matProj;
  898. pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
  899. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
  900. VMatrix matViewProj;
  901. MatrixMultiply( matProj, matView, matViewProj );
  902. float flViewportX, flViewportY, flViewportWidth, flViewportHeight;
  903. {
  904. int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
  905. pRenderContext->GetViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
  906. flViewportX = float( nViewportX );
  907. flViewportY = float( nViewportY );
  908. flViewportWidth = 0.5f * float( nViewportWidth );
  909. flViewportHeight = 0.5f * float( nViewportHeight );
  910. }
  911. //step 3, fill in stencil views (remember that in multiple depth situations that any subportals will run through this function again before this section completes, thereby screwing with stencil settings)
  912. for ( int i = 0; i < portalRenderablesToDraw.Count(); i++ )
  913. {
  914. CPortalRenderable *pCurrentPortal = portalRenderablesToDraw[i];
  915. // Hackity hack?
  916. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel + 1].RemoveAll(); //clear any previously stored complex frustum
  917. m_StencilState.m_bEnable = true;
  918. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  919. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  920. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  921. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  922. m_StencilState.m_nTestMask = 0xFF;
  923. m_StencilState.m_nWriteMask = 0xFF;
  924. m_StencilState.m_nReferenceValue = ComputeStencilRefValue( m_iViewRecursionLevel, i, nParentPortalIdx );
  925. pRenderContext->SetStencilState( m_StencilState );
  926. m_stencilValueStack.Push( m_StencilState.m_nReferenceValue );
  927. m_parentPortalIdStack.Push( i );
  928. bool bPushedScissor = false;
  929. if ( r_portalscissor.GetBool() )
  930. {
  931. Vector4D clipSpacePortalCorners[4];
  932. float flMinX = FLT_MAX;
  933. float flMinY = FLT_MAX;
  934. float flMaxX = -FLT_MAX;
  935. float flMaxY = -FLT_MAX;
  936. // Compute portal positions in clip space
  937. if ( assert_cast< CPortalRenderable_FlatBasic* >( pCurrentPortal )->ComputeClipSpacePortalCorners( clipSpacePortalCorners, matViewProj ) )
  938. {
  939. // The portal didn't clip the near plane, continue
  940. for ( int i = 0; i < 4; i++ )
  941. {
  942. float flX = clipSpacePortalCorners[i].x / clipSpacePortalCorners[i].w;
  943. float flY = -clipSpacePortalCorners[i].y / clipSpacePortalCorners[i].w;
  944. flMinX = MIN( flX, flMinX );
  945. flMinY = MIN( flY, flMinY );
  946. flMaxX = MAX( flX, flMaxX );
  947. flMaxY = MAX( flY, flMaxY );
  948. }
  949. flMinX = clamp( flMinX, -1.0f, 1.0f );
  950. flMaxX = clamp( flMaxX, -1.0f, 1.0f );
  951. flMinY = clamp( flMinY, -1.0f, 1.0f );
  952. flMaxY = clamp( flMaxY, -1.0f, 1.0f );
  953. flMinX = flViewportWidth * flMinX + flViewportWidth + flViewportX;
  954. flMaxX = flViewportWidth * flMaxX + flViewportWidth + flViewportX;
  955. flMinY = flViewportHeight * flMinY + flViewportHeight + flViewportY;
  956. flMaxY = flViewportHeight * flMaxY + flViewportHeight + flViewportY;
  957. pRenderContext->PushScissorRect( int( flMinX ), int( flMinY ), int( flMaxX ), int( flMaxY ) );
  958. bPushedScissor = true;
  959. }
  960. }
  961. //step 2, clear the depth buffer in stencil areas so we can render a new scene to them
  962. {
  963. // TODO: We could render the portal quads instead of a fullscreen quad to save fill.
  964. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step2_clear_portal_depth" );
  965. pRenderContext->ClearBuffersObeyStencil( false, true );
  966. pPortalQuadMesh = NULL; // NULL it out so we know to restore our dynamic mesh later
  967. pRenderContext->EndPIXEvent();
  968. }
  969. #ifdef _PS3
  970. // step 2.5
  971. ReloadZcullMemory();
  972. pPortalQuadMesh = NULL; // NULL it out so we know to restore our dynamic mesh later
  973. #endif // _PS3
  974. {
  975. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step3_recursive_draw" );
  976. VPROF_BUDGET( "Portal_FillInStencilViews", "Portal_FillInStencilViews" );
  977. bRebuildDrawListsWhenDone = true;
  978. MaterialFogMode_t fogModeBackup = pRenderContext->GetFogMode();
  979. unsigned char fogColorBackup[4];
  980. pRenderContext->GetFogColor( fogColorBackup );
  981. float fFogStartBackup, fFogEndBackup, fFogZBackup;
  982. pRenderContext->GetFogDistances( &fFogStartBackup, &fFogEndBackup, &fFogZBackup );
  983. CGlowOverlay::BackupSkyOverlayData( m_iViewRecursionLevel );
  984. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes.Count() > pCurrentPortal->m_iPortalViewIDNodeIndex );
  985. m_PortalViewIDNodeChain[m_iViewRecursionLevel + 1] = m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex];
  986. pCurrentPortal->RenderPortalViewToBackBuffer( pViewRender, *pViewSetup );
  987. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_PORTAL_RECURSION_DEPTH, m_iViewRecursionLevel ); // restore portal recursion depth param
  988. m_PortalViewIDNodeChain[m_iViewRecursionLevel + 1] = NULL;
  989. // This value is incremented to signal that we need to re-copy the refract texture
  990. // because we've finished rendering a child portal and its translucent pass, and we're about
  991. // to render the parent portal's translucent pass or another portal
  992. ++ g_nCurrentPortalRender;
  993. CGlowOverlay::RestoreSkyOverlayData( m_iViewRecursionLevel );
  994. memcpy( (void *)pViewSetup, &ViewBackup, sizeof( CViewSetup ) );
  995. pViewRender->m_pActiveRenderer->EnableWorldFog();
  996. pRenderContext->FogMode( fogModeBackup );
  997. pRenderContext->FogColor3ubv( fogColorBackup );
  998. pRenderContext->FogStart( fFogStartBackup );
  999. pRenderContext->FogEnd( fFogEndBackup );
  1000. pRenderContext->SetFogZ( fFogZBackup );
  1001. pRenderContext->EndPIXEvent();
  1002. }
  1003. //step 4, patch up the fact that we just made a hole in the wall because it's not *really* a hole at all
  1004. //step 5, restore the stencil mask to the parent level
  1005. {
  1006. // We restore it right away instead of after opening all holes for 360 perf. Apparently the 360 runs the shaders when Z passes even if stencil fails later.
  1007. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step4_restore_depthstencil" );
  1008. m_StencilState.m_bEnable = true;
  1009. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_NOTEQUAL;
  1010. m_StencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  1011. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1012. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1013. m_StencilState.m_nTestMask = ComputeStencilRestoreTestMask( m_iViewRecursionLevel, i );
  1014. m_StencilState.m_nWriteMask = m_StencilState.m_nTestMask;
  1015. m_StencilState.m_nReferenceValue = 0;
  1016. pRenderContext->SetStencilState( m_StencilState );
  1017. if ( pPortalQuadMesh == NULL )
  1018. {
  1019. Assert( m_pCachedPortalQuadMeshData );
  1020. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  1021. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  1022. }
  1023. pRenderContext->Bind( (IMaterial*)( const IMaterial *)( m_MaterialsAccess.m_WriteZ_Model ), static_cast< CPortalRenderable_FlatBasic* >( pCurrentPortal )->GetClientRenderable() );
  1024. int nStartIndex = portalsRenderablesToDrawVBIndex[i] * 6;
  1025. int nIndexCount = 6;
  1026. pRenderContext->OverrideDepthEnable( true, true, false ); // Force depth writes on, but depth test off
  1027. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  1028. if ( ( m_iViewRecursionLevel == 0 ) && ( m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nStartIndex >= 0 ) )
  1029. {
  1030. // Draw near plane cap
  1031. nStartIndex = m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nStartIndex;
  1032. nIndexCount = m_clampedPortalMeshRenderInfos[ portalsRenderablesToDrawVBIndex[i] ].nIndexCount;
  1033. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  1034. }
  1035. pRenderContext->OverrideDepthEnable( false, true, true );
  1036. pRenderContext->EndPIXEvent();
  1037. }
  1038. #ifdef _PS3
  1039. // step 2.5
  1040. ReloadZcullMemory();
  1041. pPortalQuadMesh = NULL; // NULL it out so we know to restore our dynamic mesh later
  1042. #endif // _PS3
  1043. if ( bPushedScissor )
  1044. {
  1045. pRenderContext->PopScissorRect();
  1046. }
  1047. }
  1048. int nParentStencilValue = 0;
  1049. m_stencilValueStack.Pop( nParentStencilValue );
  1050. //step 6, go back to non-stencil rendering mode in preparation to resume normal scene rendering
  1051. if( m_iViewRecursionLevel == 0 )
  1052. {
  1053. Assert( m_pRenderingViewForPortal == NULL );
  1054. Assert( m_pRenderingViewExitPortal == NULL );
  1055. m_pRenderingViewExitPortal = NULL;
  1056. m_pRenderingViewForPortal = NULL;
  1057. m_StencilState.m_bEnable = false;
  1058. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_NEVER;
  1059. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1060. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1061. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1062. m_StencilState.m_nTestMask = 0;
  1063. m_StencilState.m_nWriteMask = 0;
  1064. m_StencilState.m_nReferenceValue = 0;
  1065. pRenderContext->SetStencilState( m_StencilState );
  1066. m_RecursiveViewComplexFrustums[0].RemoveAll();
  1067. }
  1068. else
  1069. {
  1070. m_StencilState.m_bEnable = true;
  1071. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  1072. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1073. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1074. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1075. m_StencilState.m_nTestMask = 0xFF;
  1076. m_StencilState.m_nWriteMask = 0xFF;
  1077. m_StencilState.m_nReferenceValue = nParentStencilValue;
  1078. pRenderContext->SetStencilState( m_StencilState );
  1079. }
  1080. if( bRebuildDrawListsWhenDone )
  1081. {
  1082. memcpy( (void *)pViewSetup, &ViewBackup, sizeof( CViewSetup ) ); //if we don't restore this, the view is permanently altered (in mid render of an existing scene)
  1083. }
  1084. pRenderContext->Flush( true ); //just in case
  1085. ++m_iRemainingPortalViewDepth;
  1086. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_DrawPortalsEnd" );
  1087. if ( pPortalQuadMesh == NULL )
  1088. {
  1089. Assert( m_pCachedPortalQuadMeshData );
  1090. pPortalQuadMesh = pRenderContext->GetDynamicMeshEx( m_portalQuadMeshVertexFmt );
  1091. pPortalQuadMesh->ReconstructFromCachedPerFrameMeshData( m_pCachedPortalQuadMeshData );
  1092. }
  1093. RenderPortalEffects( pRenderContext, pPortalQuadMesh, actualActivePortals, actualActivePortalQuadVBIndex );
  1094. pRenderContext->EndPIXEvent();
  1095. if ( pPortalQuadMesh )
  1096. {
  1097. pPortalQuadMesh->MarkAsDrawn();
  1098. }
  1099. return bRebuildDrawListsWhenDone;
  1100. }
  1101. void CPortalRender::RenderPortalEffects( IMatRenderContext *pRenderContext, IMesh *pPortalQuadMesh, const CUtlVector< CPortalRenderable* > &actualActivePortals, const CUtlVector< int > &actualActivePortalQuadVBIndex ) const
  1102. {
  1103. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1104. pRenderContext->PushMatrix();
  1105. for( int i = 0; i < actualActivePortals.Count(); ++i )
  1106. {
  1107. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  1108. if ( !pCurrentPortal->IsPropPortal() )
  1109. {
  1110. continue;
  1111. }
  1112. C_Prop_Portal *pPropPortal = (C_Prop_Portal *)pCurrentPortal;
  1113. bool bDrawRing = true;
  1114. int nRenderPassCount = pCurrentPortal->BindPortalMaterial( pRenderContext, 0, &bDrawRing );
  1115. bDrawRing = bDrawRing && ( pPropPortal->ComputeStaticAmountForRendering() == 0.0f ) && ( pPropPortal->m_fOpenAmount >= 0.99f );
  1116. int nStartIndex = bDrawRing ? m_clampedPortalMeshRenderInfos.Tail().nStartIndex : actualActivePortalQuadVBIndex[i] * 6;
  1117. int nIndexCount = bDrawRing ? m_clampedPortalMeshRenderInfos.Tail().nIndexCount : 6;
  1118. if ( bDrawRing )
  1119. {
  1120. matrix3x4_t matObjToWorld( pPropPortal->m_vRight, pPropPortal->m_vUp, pPropPortal->m_vForward, pPropPortal->m_ptOrigin );
  1121. pRenderContext->LoadMatrix( matObjToWorld );
  1122. }
  1123. else
  1124. {
  1125. pRenderContext->LoadIdentity();
  1126. }
  1127. if ( nRenderPassCount > 0 )
  1128. {
  1129. // Draw first pass
  1130. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  1131. }
  1132. if ( nRenderPassCount > 1 )
  1133. {
  1134. bool bDummy;
  1135. pCurrentPortal->BindPortalMaterial( pRenderContext, 1, &bDummy );
  1136. // Draw 2nd pass
  1137. pPortalQuadMesh->Draw( nStartIndex, nIndexCount );
  1138. }
  1139. Assert( nRenderPassCount <= 2 );
  1140. }
  1141. pRenderContext->PopMatrix();
  1142. }
  1143. //-----------------------------------------------------------------------------------------------------------------------------------
  1144. //-----------------------------------------------------------------------------------------------------------------------------------
  1145. //-----------------------------------------------------------------------------------------------------------------------------------
  1146. //-----------------------------------------------------------------------------------------------------------------------------------
  1147. //-----------------------------------------------------------------------------------------------------------------------------------
  1148. //-----------------------------------------------------------------------------------------------------------------------------------
  1149. bool CPortalRender::DrawPortalsUsingStencils_Old( CViewRender *pViewRender )
  1150. {
  1151. int iDrawFlags = pViewRender->GetDrawFlags();
  1152. if ( (iDrawFlags & DF_RENDER_REFLECTION) != 0 )
  1153. return false;
  1154. if ( ((iDrawFlags & DF_CLIP_Z) != 0) && ((iDrawFlags & DF_CLIP_BELOW) == 0) ) //clipping above the water height
  1155. return false;
  1156. CMatRenderContextPtr pRenderContext( materials );
  1157. int iNumRenderablePortals = m_ActivePortals.Count();
  1158. // This loop is necessary because tools can suppress rendering without telling the portal system
  1159. CUtlVector< CPortalRenderable* > actualActivePortals( 0, iNumRenderablePortals );
  1160. for ( int i = 0; i < iNumRenderablePortals; ++i )
  1161. {
  1162. CPortalRenderable *pPortalRenderable = m_ActivePortals[i];
  1163. C_BaseEntity *pPairedEntity = pPortalRenderable->PortalRenderable_GetPairedEntity();
  1164. bool bIsVisible = (pPairedEntity == NULL) || (pPairedEntity->IsVisible() && pPairedEntity->ShouldDraw()); //either unknown visibility or definitely visible.
  1165. // If the portal is associated with an entity, check to see if that entity is even in the PVS before rendering the portal
  1166. if ( pPairedEntity != NULL && r_portal_use_pvs_optimization.GetBool() )
  1167. {
  1168. IClientRenderable *pCR = pPairedEntity->GetClientRenderable();
  1169. bool bIsRenderable = g_pClientLeafSystem->IsRenderableInPVS( pCR );
  1170. bIsVisible &= bIsRenderable;
  1171. }
  1172. if ( !pPortalRenderable->m_bIsPlaybackPortal )
  1173. {
  1174. if ( !bIsVisible )
  1175. {
  1176. //can't see through the portal, free up it's view id node for use elsewhere
  1177. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] != NULL )
  1178. {
  1179. FreePortalViewIDNode( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] );
  1180. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortalRenderable->m_iPortalViewIDNodeIndex] = NULL;
  1181. }
  1182. continue;
  1183. }
  1184. }
  1185. actualActivePortals.AddToTail( m_ActivePortals[i] );
  1186. }
  1187. iNumRenderablePortals = actualActivePortals.Count();
  1188. #ifdef PORTAL
  1189. if( !ToolsEnabled() )
  1190. {
  1191. VPROF_BUDGET( "PortalGhosts", "PortalGhosts" );
  1192. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal Ghosts" );
  1193. C_Prop_Portal::DrawPortalGhostLocations( pRenderContext ); //we want to show where the portals are through walls, but not if occluded by a portal view, otherwise we're showing the player confusing data. This is the best place to wedge this
  1194. pRenderContext->EndPIXEvent();
  1195. }
  1196. #endif
  1197. if( iNumRenderablePortals == 0 )
  1198. return false;
  1199. const int iMaxDepth = MIN( r_portal_stencil_depth.GetInt(), MIN( MAX_PORTAL_RECURSIVE_VIEWS, (1 << materials->StencilBufferBits()) ) - 1 );
  1200. if( m_iViewRecursionLevel >= iMaxDepth ) //can't support any more views
  1201. {
  1202. m_iRemainingPortalViewDepth = 0; //special case handler for max depth 0 cases
  1203. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_maxrecursion_reached" );
  1204. for( int i = 0; i != iNumRenderablePortals; ++i )
  1205. {
  1206. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  1207. pCurrentPortal->DrawPortal( pRenderContext );
  1208. }
  1209. pRenderContext->EndPIXEvent();
  1210. return false;
  1211. }
  1212. m_iRemainingPortalViewDepth = (iMaxDepth - m_iViewRecursionLevel) - 1;
  1213. pRenderContext->Flush( true ); //to prevent screwing up the last opaque object
  1214. const CViewSetup *pViewSetup = pViewRender->GetViewSetup();
  1215. m_RecursiveViewSetups[m_iViewRecursionLevel] = *pViewSetup;
  1216. CViewSetup ViewBackup;// = *pViewSetup; //backup the view, we'll need to restore it
  1217. memcpy( &ViewBackup, pViewSetup, sizeof( CViewSetup ) );
  1218. Vector ptCameraOrigin = pViewSetup->origin;
  1219. Vector vCameraForward;
  1220. AngleVectors( pViewSetup->angles, &vCameraForward, NULL, NULL );
  1221. int iX, iY, iWidth, iHeight;
  1222. pRenderContext->GetViewport( iX, iY, iWidth, iHeight );
  1223. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  1224. int iScreenPixelCount = iWidth * iHeight;
  1225. #endif
  1226. bool bRebuildDrawListsWhenDone = false;
  1227. int iParentLevelStencilReferenceValue = m_iViewRecursionLevel;
  1228. int iStencilReferenceValue = iParentLevelStencilReferenceValue + 1;
  1229. if( m_iViewRecursionLevel == 0 ) //first entry into the stencil drawing
  1230. {
  1231. m_StencilState.m_bEnable = true;
  1232. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  1233. m_StencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  1234. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1235. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1236. m_StencilState.m_nTestMask = 0xFF;
  1237. m_StencilState.m_nWriteMask = 0xFF;
  1238. m_StencilState.m_nReferenceValue = 0;
  1239. pRenderContext->SetStencilState( m_StencilState );
  1240. pRenderContext->PerformFullScreenStencilOperation();
  1241. m_RecursiveViewComplexFrustums[0].RemoveAll(); //clear any garbage leftover in the complex frustums from last frame
  1242. }
  1243. if( m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].Count() == 0 )
  1244. {
  1245. //nothing in the complex frustum from the current view, copy the standard frustum in
  1246. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel].AddMultipleToTail( FRUSTUM_NUMPLANES, pViewRender->GetFrustum() );
  1247. }
  1248. for( int i = 0; i < iNumRenderablePortals; ++i )
  1249. {
  1250. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  1251. m_RecursiveViewComplexFrustums[m_iViewRecursionLevel + 1].RemoveAll(); //clear any previously stored complex frustum
  1252. if( (pCurrentPortal->GetLinkedPortal() == NULL) ||
  1253. (pCurrentPortal == m_pRenderingViewExitPortal) ||
  1254. (pCurrentPortal->ShouldUpdatePortalView_BasedOnView( *pViewSetup, m_RecursiveViewComplexFrustums[m_iViewRecursionLevel] ) == false) )
  1255. {
  1256. //can't see through the portal, free up it's view id node for use elsewhere
  1257. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] != NULL )
  1258. {
  1259. FreePortalViewIDNode( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] );
  1260. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] = NULL;
  1261. }
  1262. continue;
  1263. }
  1264. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes.Count() > pCurrentPortal->m_iPortalViewIDNodeIndex );
  1265. if( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] == NULL )
  1266. {
  1267. C_Prop_Portal *pPropPortal = static_cast<C_Prop_Portal*>( pCurrentPortal );
  1268. int nPortalIndex = pPropPortal->m_bIsPortal2 ? 1 : 0;
  1269. int nTeamIndex = pPropPortal->GetTeamNumber();
  1270. m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex] = AllocPortalViewIDNode( m_HeadPortalViewIDNode.ChildNodes.Count(), nPortalIndex, nTeamIndex, CurrentViewID() );
  1271. }
  1272. // PortalViewIDNode_t *pCurrentPortalViewNode = m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex];
  1273. // Step 0, Allow for special effects to happen before cutting a hole
  1274. {
  1275. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step0" );
  1276. m_StencilState.m_bEnable = true;
  1277. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  1278. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1279. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1280. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1281. m_StencilState.m_nTestMask = 0xFF;
  1282. m_StencilState.m_nWriteMask = 0xFF;
  1283. m_StencilState.m_nReferenceValue = iParentLevelStencilReferenceValue;
  1284. pRenderContext->SetStencilState( m_StencilState );
  1285. pCurrentPortal->DrawPreStencilMask( pRenderContext );
  1286. pRenderContext->EndPIXEvent();
  1287. }
  1288. //step 1, write out the stencil values (and colors if you want, but really not necessary)
  1289. {
  1290. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step1" );
  1291. m_StencilState.m_PassOp = SHADER_STENCILOP_INCREMENT_CLAMP;
  1292. pRenderContext->SetStencilState( m_StencilState );
  1293. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  1294. pRenderContext->BeginOcclusionQueryDrawing( pCurrentPortalViewNode->occlusionQueryHandle );
  1295. pCurrentPortalViewNode->iWindowPixelsAtQueryTime = iScreenPixelCount;
  1296. #endif
  1297. pCurrentPortal->DrawStencilMask( pRenderContext );
  1298. #ifndef TEMP_DISABLE_PORTAL_VIS_QUERY
  1299. pRenderContext->EndOcclusionQueryDrawing( pCurrentPortalViewNode->occlusionQueryHandle );
  1300. #endif
  1301. pRenderContext->EndPIXEvent();
  1302. }
  1303. {
  1304. //step 2, clear the depth buffer in stencil areas so we can render a new scene to them
  1305. {
  1306. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step2" );
  1307. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1308. m_StencilState.m_nReferenceValue = iStencilReferenceValue;
  1309. pRenderContext->SetStencilState( m_StencilState );
  1310. pRenderContext->ClearBuffersObeyStencil( false, true );
  1311. pRenderContext->EndPIXEvent();
  1312. }
  1313. #ifdef _PS3
  1314. // step 2.5
  1315. ReloadZcullMemory();
  1316. #endif // _PS3
  1317. //step 3, fill in stencil views (remember that in multiple depth situations that any subportals will run through this function again before this section completes, thereby screwing with stencil settings)
  1318. {
  1319. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step3" );
  1320. // VPROF_BUDGET( "Portal_FillInStencilViews", "Portal_FillInStencilViews" );
  1321. bRebuildDrawListsWhenDone = true;
  1322. MaterialFogMode_t fogModeBackup = pRenderContext->GetFogMode();
  1323. unsigned char fogColorBackup[4];
  1324. pRenderContext->GetFogColor( fogColorBackup );
  1325. float fFogStartBackup, fFogEndBackup, fFogZBackup;
  1326. pRenderContext->GetFogDistances( &fFogStartBackup, &fFogEndBackup, &fFogZBackup );
  1327. CGlowOverlay::BackupSkyOverlayData( m_iViewRecursionLevel );
  1328. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes.Count() > pCurrentPortal->m_iPortalViewIDNodeIndex );
  1329. m_PortalViewIDNodeChain[m_iViewRecursionLevel + 1] = m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pCurrentPortal->m_iPortalViewIDNodeIndex];
  1330. if ( r_portalstencildisable.GetBool() )
  1331. {
  1332. m_StencilState.m_bEnable = true;
  1333. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  1334. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1335. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1336. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1337. m_StencilState.m_nTestMask = 0xFF;
  1338. m_StencilState.m_nWriteMask = 0xFF;
  1339. m_StencilState.m_nReferenceValue = iStencilReferenceValue;
  1340. pRenderContext->SetStencilState( m_StencilState );
  1341. pRenderContext->ClearBuffers( true, true );
  1342. }
  1343. pCurrentPortal->RenderPortalViewToBackBuffer( pViewRender, *pViewSetup );
  1344. m_PortalViewIDNodeChain[m_iViewRecursionLevel + 1] = NULL;
  1345. // This value is incremented to signal that we need to re-copy the refract texture
  1346. // because we've finished rendering a child portal and its translucent pass, and we're about
  1347. // to render the parent portal's translucent pass or another portal
  1348. ++ g_nCurrentPortalRender;
  1349. CGlowOverlay::RestoreSkyOverlayData( m_iViewRecursionLevel );
  1350. memcpy( (void *)pViewSetup, &ViewBackup, sizeof( CViewSetup ) );
  1351. pViewRender->m_pActiveRenderer->EnableWorldFog();
  1352. pRenderContext->FogMode( fogModeBackup );
  1353. pRenderContext->FogColor3ubv( fogColorBackup );
  1354. pRenderContext->FogStart( fFogStartBackup );
  1355. pRenderContext->FogEnd( fFogEndBackup );
  1356. pRenderContext->SetFogZ( fFogZBackup );
  1357. //do a full reset of what we think the stencil operations are in case the recursive calls got weird
  1358. m_StencilState.m_bEnable = true;
  1359. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  1360. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1361. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1362. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1363. m_StencilState.m_nTestMask = 0xFF;
  1364. m_StencilState.m_nWriteMask = 0xFF;
  1365. m_StencilState.m_nReferenceValue = iStencilReferenceValue;
  1366. pRenderContext->SetStencilState( m_StencilState );
  1367. pRenderContext->EndPIXEvent();
  1368. }
  1369. //step 4, patch up the fact that we just made a hole in the wall because it's not *really* a hole at all
  1370. {
  1371. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step4" );
  1372. pCurrentPortal->DrawPostStencilFixes( pRenderContext );
  1373. pRenderContext->EndPIXEvent();
  1374. }
  1375. }
  1376. //step 5, restore the stencil mask to the parent level
  1377. {
  1378. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_Step5" );
  1379. m_StencilState.m_PassOp = SHADER_STENCILOP_DECREMENT_CLAMP;
  1380. pRenderContext->SetStencilState( m_StencilState );
  1381. pRenderContext->PerformFullScreenStencilOperation();
  1382. pRenderContext->EndPIXEvent();
  1383. }
  1384. }
  1385. //step 6, go back to non-stencil rendering mode in preparation to resume normal scene rendering
  1386. if( m_iViewRecursionLevel == 0 )
  1387. {
  1388. Assert( m_pRenderingViewForPortal == NULL );
  1389. Assert( m_pRenderingViewExitPortal == NULL );
  1390. m_pRenderingViewExitPortal = NULL;
  1391. m_pRenderingViewForPortal = NULL;
  1392. m_StencilState.m_bEnable = false;
  1393. m_StencilState.m_CompareFunc = SHADER_STENCILFUNC_NEVER;
  1394. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1395. m_StencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1396. m_StencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1397. m_StencilState.m_nTestMask = 0;
  1398. m_StencilState.m_nWriteMask = 0;
  1399. m_StencilState.m_nReferenceValue = 0;
  1400. pRenderContext->SetStencilState( m_StencilState );
  1401. m_RecursiveViewComplexFrustums[0].RemoveAll();
  1402. }
  1403. else
  1404. {
  1405. m_StencilState.m_PassOp = SHADER_STENCILOP_KEEP;
  1406. m_StencilState.m_nReferenceValue = iParentLevelStencilReferenceValue;
  1407. pRenderContext->SetStencilState( m_StencilState );
  1408. }
  1409. if( bRebuildDrawListsWhenDone )
  1410. {
  1411. memcpy( (void *)pViewSetup, &ViewBackup, sizeof( CViewSetup ) ); //if we don't restore this, the view is permanently altered (in mid render of an existing scene)
  1412. }
  1413. pRenderContext->Flush( true ); //just in case
  1414. ++m_iRemainingPortalViewDepth;
  1415. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "Portal_DrawPortalsEnd" );
  1416. for( int i = 0; i < iNumRenderablePortals; ++i )
  1417. {
  1418. CPortalRenderable *pCurrentPortal = actualActivePortals[i];
  1419. pCurrentPortal->DrawPortal( pRenderContext );
  1420. }
  1421. pRenderContext->EndPIXEvent();
  1422. return bRebuildDrawListsWhenDone;
  1423. }
  1424. //-----------------------------------------------------------------------------------------------------------------------------------
  1425. //-----------------------------------------------------------------------------------------------------------------------------------
  1426. //-----------------------------------------------------------------------------------------------------------------------------------
  1427. //-----------------------------------------------------------------------------------------------------------------------------------
  1428. //-----------------------------------------------------------------------------------------------------------------------------------
  1429. //-----------------------------------------------------------------------------------------------------------------------------------
  1430. void CPortalRender::AddPortal( CPortalRenderable *pPortal )
  1431. {
  1432. for( int i = m_ActivePortals.Count(); --i >= 0; )
  1433. {
  1434. if( m_ActivePortals[i] == pPortal )
  1435. return;
  1436. }
  1437. m_ActivePortals.AddToTail( pPortal );
  1438. }
  1439. void CPortalRender::RemovePortal( CPortalRenderable *pPortal )
  1440. {
  1441. for( int i = m_ActivePortals.Count(); --i >= 0; )
  1442. {
  1443. if( m_ActivePortals[i] == pPortal )
  1444. {
  1445. m_ActivePortals.FastRemove( i );
  1446. return;
  1447. }
  1448. }
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Are we currently rendering a portal?
  1452. //-----------------------------------------------------------------------------
  1453. bool CPortalRender::IsRenderingPortal() const
  1454. {
  1455. return m_pRenderingViewForPortal != NULL;
  1456. }
  1457. //-----------------------------------------------------------------------------
  1458. // Returns view recursion level
  1459. //-----------------------------------------------------------------------------
  1460. int CPortalRender::GetViewRecursionLevel() const
  1461. {
  1462. return m_iViewRecursionLevel;
  1463. }
  1464. //-----------------------------------------------------------------------------
  1465. //normalized for how many of the screen's possible pixels it takes up, less than zero indicates a lack of data from last frame
  1466. //-----------------------------------------------------------------------------
  1467. float CPortalRender::GetPixelVisilityForPortalSurface( const CPortalRenderable *pPortal ) const
  1468. {
  1469. PortalViewIDNode_t *pNode = m_PortalViewIDNodeChain[m_iViewRecursionLevel]->ChildNodes[pPortal->m_iPortalViewIDNodeIndex];
  1470. if( pNode )
  1471. return pNode->fScreenFilledByPortalSurfaceLastFrame_Normalized;
  1472. return -1.0f;
  1473. }
  1474. //-----------------------------------------------------------------------------
  1475. // Methods to query about the exit portal associated with the currently rendering portal
  1476. //-----------------------------------------------------------------------------
  1477. const Vector &CPortalRender::GetExitPortalFogOrigin() const
  1478. {
  1479. return m_pRenderingViewExitPortal->GetFogOrigin();
  1480. }
  1481. void CPortalRender::ShiftFogForExitPortalView() const
  1482. {
  1483. if ( m_pRenderingViewExitPortal )
  1484. {
  1485. m_pRenderingViewExitPortal->ShiftFogForExitPortalView();
  1486. }
  1487. }
  1488. float CPortalRender::GetCurrentPortalDistanceBias() const
  1489. {
  1490. if ( m_pRenderingViewExitPortal )
  1491. {
  1492. return m_pRenderingViewExitPortal->GetPortalDistanceBias();
  1493. }
  1494. return 0.0f;
  1495. }
  1496. void CPortalRenderable::ShiftFogForExitPortalView() const
  1497. {
  1498. CMatRenderContextPtr pRenderContext( materials );
  1499. float fFogStart, fFogEnd, fFogZ;
  1500. pRenderContext->GetFogDistances( &fFogStart, &fFogEnd, &fFogZ );
  1501. Vector vFogOrigin = GetFogOrigin();
  1502. Vector vCameraToExitPortal = vFogOrigin - CurrentViewOrigin();
  1503. float fDistModifier = vCameraToExitPortal.Dot( CurrentViewForward() );
  1504. fFogStart += fDistModifier;
  1505. fFogEnd += fDistModifier;
  1506. //fFogZ += something; //FIXME: find out what the hell to do with this
  1507. pRenderContext->FogStart( fFogStart );
  1508. pRenderContext->FogEnd( fFogEnd );
  1509. pRenderContext->SetFogZ( fFogZ );
  1510. }
  1511. SkyboxVisibility_t CPortalRender::IsSkyboxVisibleFromExitPortal() const
  1512. {
  1513. return m_pRenderingViewExitPortal->SkyBoxVisibleFromPortal();
  1514. }
  1515. bool CPortalRender::DoesExitPortalViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const
  1516. {
  1517. return m_pRenderingViewExitPortal->DoesExitViewIntersectWaterPlane( waterZ, leafWaterDataID );
  1518. }
  1519. //-----------------------------------------------------------------------------
  1520. // Returns the remaining number of portals to render within other portals
  1521. // lets portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
  1522. //-----------------------------------------------------------------------------
  1523. int CPortalRender::GetRemainingPortalViewDepth() const
  1524. {
  1525. return m_iRemainingPortalViewDepth;
  1526. }
  1527. //-----------------------------------------------------------------------------
  1528. // Returns the current View IDs
  1529. //-----------------------------------------------------------------------------
  1530. int CPortalRender::GetCurrentViewId() const
  1531. {
  1532. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel] != NULL );
  1533. #ifdef _DEBUG
  1534. for( int i = 0; i != m_iViewRecursionLevel; ++i )
  1535. {
  1536. Assert( m_PortalViewIDNodeChain[i]->iPrimaryViewID != m_PortalViewIDNodeChain[m_iViewRecursionLevel]->iPrimaryViewID );
  1537. }
  1538. #endif
  1539. return m_PortalViewIDNodeChain[m_iViewRecursionLevel]->iPrimaryViewID;
  1540. }
  1541. int CPortalRender::GetCurrentSkyboxViewId() const
  1542. {
  1543. Assert( m_PortalViewIDNodeChain[m_iViewRecursionLevel] != NULL );
  1544. return m_PortalViewIDNodeChain[m_iViewRecursionLevel]->iPrimaryViewID + 1;
  1545. }
  1546. void OverlayCameraRenderTarget( const char *pszMaterialName, float flX, float flY, float w, float h ); //implemented in view_scene.cpp
  1547. void CPortalRender::OverlayPortalRenderTargets( float w, float h )
  1548. {
  1549. OverlayCameraRenderTarget( "engine/debug_portal_1", 0,0, w,h );
  1550. OverlayCameraRenderTarget( "engine/debug_portal_2", w+10,0, w,h );
  1551. OverlayCameraRenderTarget( "engine/debug_water_reflect_0", 0, h+10, w,h );
  1552. OverlayCameraRenderTarget( "engine/debug_water_reflect_1", w+10, h+10, w,h );
  1553. OverlayCameraRenderTarget( "engine/debug_water_reflect_2", (w+10) * 2, h+10, w,h );
  1554. OverlayCameraRenderTarget( "engine/debug_water_refract_0", 0, (h+10) * 2, w,h );
  1555. OverlayCameraRenderTarget( "engine/debug_water_refract_1", w+10, (h+10) * 2, w,h );
  1556. OverlayCameraRenderTarget( "engine/debug_water_refract_2", (w+10) * 2, (h+10) * 2, w,h );
  1557. }
  1558. void CPortalRender::UpdateDepthDoublerTexture( const CViewSetup &viewSetup )
  1559. {
  1560. if( DepthDoublerPIPDisableCheck() )
  1561. return;
  1562. bool bShouldUpdate = false;
  1563. for( int i = m_ActivePortals.Count(); --i >= 0; )
  1564. {
  1565. CPortalRenderable *pPortal = m_ActivePortals[i];
  1566. if( pPortal->ShouldUpdateDepthDoublerTexture( viewSetup ) )
  1567. {
  1568. bShouldUpdate = true;
  1569. break;
  1570. }
  1571. }
  1572. if( bShouldUpdate )
  1573. {
  1574. Rect_t srcRect;
  1575. srcRect.x = viewSetup.x;
  1576. srcRect.y = viewSetup.y;
  1577. srcRect.width = viewSetup.width;
  1578. srcRect.height = viewSetup.height;
  1579. ITexture *pTexture = portalrendertargets->GetDepthDoublerTexture();
  1580. CMatRenderContextPtr pRenderContext( materials );
  1581. pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, &srcRect );
  1582. }
  1583. }
  1584. bool CPortalRender::DepthDoublerPIPDisableCheck( void )
  1585. {
  1586. int slot = GET_ACTIVE_SPLITSCREEN_SLOT();
  1587. return (slot != 0) && VGui_IsSplitScreenPIP();
  1588. }
  1589. //-----------------------------------------------------------------------------
  1590. // Finds a recorded portal
  1591. //-----------------------------------------------------------------------------
  1592. int CPortalRender::FindRecordedPortalIndex( int nPortalId )
  1593. {
  1594. int nCount = m_RecordedPortals.Count();
  1595. for ( int i = 0; i < nCount; ++i )
  1596. {
  1597. if ( m_RecordedPortals[i].m_nPortalId == nPortalId )
  1598. return i;
  1599. }
  1600. return -1;
  1601. }
  1602. CPortalRenderable* CPortalRender::FindRecordedPortal( int nPortalId )
  1603. {
  1604. int nIndex = FindRecordedPortalIndex( nPortalId );
  1605. return ( nIndex >= 0 ) ? m_RecordedPortals[nIndex].m_pActivePortal : NULL;
  1606. }
  1607. CPortalRenderable* CPortalRender::FindRecordedPortal( IClientRenderable *pRenderable )
  1608. {
  1609. int nCount = m_RecordedPortals.Count();
  1610. for ( int i = 0; i < nCount; ++i )
  1611. {
  1612. if ( m_RecordedPortals[i].m_pPlaybackRenderable == pRenderable )
  1613. return m_RecordedPortals[i].m_pActivePortal;
  1614. }
  1615. return NULL;
  1616. }
  1617. //-----------------------------------------------------------------------------
  1618. // Handles a portal update message
  1619. //-----------------------------------------------------------------------------
  1620. void CPortalRender::HandlePortalPlaybackMessage( KeyValues *pKeyValues )
  1621. {
  1622. // Iterate through all the portal ids of all the portals in the keyvalues message
  1623. CUtlVector<int> foundIds;
  1624. for ( KeyValues *pCurr = pKeyValues->GetFirstTrueSubKey(); pCurr; pCurr = pCurr->GetNextTrueSubKey() )
  1625. {
  1626. // Create new area portals for those ids that don't exist
  1627. int nPortalId = pCurr->GetInt( "portalId" );
  1628. IClientRenderable *pRenderable = (IClientRenderable*)pCurr->GetPtr( "clientRenderable" );
  1629. int nIndex = FindRecordedPortalIndex( nPortalId );
  1630. if ( nIndex < 0 )
  1631. {
  1632. CPortalRenderable *pPortal = NULL;
  1633. const char *szType = pCurr->GetString( "portalType", "Flat Basic" ); //"Flat Basic" being the type commonly found in "Portal" mod
  1634. //search through registered creation functions for one that makes this type of portal
  1635. const CPortalRenderableCreator_AutoRegister *pCreationFuncs = CPortalRenderableCreator_AutoRegister::s_pRegisteredTypes;
  1636. while( pCreationFuncs != NULL )
  1637. {
  1638. if( FStrEq( szType, pCreationFuncs->m_szPortalType ) )
  1639. {
  1640. pPortal = pCreationFuncs->m_creationFunc();
  1641. break;
  1642. }
  1643. pCreationFuncs = pCreationFuncs->m_pNext;
  1644. }
  1645. if( pPortal == NULL )
  1646. {
  1647. AssertMsg( false, "Unable to find creation function for portal type." );
  1648. Warning( "CPortalRender::HandlePortalPlaybackMessage() unable to find creation function for portal type: %s\n", szType );
  1649. }
  1650. else
  1651. {
  1652. pPortal->m_bIsPlaybackPortal = true;
  1653. int k = m_RecordedPortals.AddToTail( );
  1654. m_RecordedPortals[k].m_pActivePortal = pPortal;
  1655. m_RecordedPortals[k].m_nPortalId = nPortalId;
  1656. m_RecordedPortals[k].m_pPlaybackRenderable = pRenderable;
  1657. AddPortal( pPortal );
  1658. }
  1659. }
  1660. else
  1661. {
  1662. m_RecordedPortals[nIndex].m_pPlaybackRenderable = pRenderable;
  1663. }
  1664. foundIds.AddToTail( nPortalId );
  1665. }
  1666. // Delete portals that didn't appear in the list
  1667. int nFoundCount = foundIds.Count();
  1668. int nCount = m_RecordedPortals.Count();
  1669. for ( int i = nCount; --i >= 0; )
  1670. {
  1671. int j;
  1672. for ( j = 0; j < nFoundCount; ++j )
  1673. {
  1674. if ( foundIds[j] == m_RecordedPortals[i].m_nPortalId )
  1675. break;
  1676. }
  1677. if ( j == nFoundCount )
  1678. {
  1679. RemovePortal( m_RecordedPortals[i].m_pActivePortal );
  1680. delete m_RecordedPortals[i].m_pActivePortal;
  1681. m_RecordedPortals.FastRemove(i);
  1682. }
  1683. }
  1684. // Iterate through all the portal ids of all the portals in the keyvalues message
  1685. for ( KeyValues *pCurr = pKeyValues->GetFirstTrueSubKey(); pCurr; pCurr = pCurr->GetNextTrueSubKey() )
  1686. {
  1687. // Update the state of the portals based on the recorded info
  1688. int nPortalId = pCurr->GetInt( "portalId" );
  1689. CPortalRenderable *pPortal = FindRecordedPortal( nPortalId );
  1690. Assert( pPortal );
  1691. pPortal->HandlePortalPlaybackMessage( pCurr );
  1692. }
  1693. // Make the portals update their internal state
  1694. /*nCount = m_RecordedPortals.Count();
  1695. for ( int i = 0; i < nCount; ++i )
  1696. {
  1697. m_RecordedPortals[i].m_pActivePortal->PortalMoved();
  1698. m_RecordedPortals[i].m_pActivePortal->ComputeLinkMatrix();
  1699. }*/
  1700. }
  1701. bool Recursive_IsPortalViewID( PortalViewIDNode_t *pNode, view_id_t id )
  1702. {
  1703. if ( pNode->iPrimaryViewID == id )
  1704. return true;
  1705. for( int i = pNode->ChildNodes.Count(); --i >= 0; )
  1706. {
  1707. PortalViewIDNode_t *pChildNode = pNode->ChildNodes[i];
  1708. if( pChildNode )
  1709. {
  1710. return Recursive_IsPortalViewID( pChildNode, id );
  1711. }
  1712. }
  1713. return false;
  1714. }
  1715. //-----------------------------------------------------------------------------
  1716. // Purpose: Tests the parameter view ID against ID's used by portal pixel vis queries
  1717. // Input : id - id tested against used portal view ids
  1718. // Output : Returns true if id matches an ID used by a portal, or it's recursive sub portals
  1719. //-----------------------------------------------------------------------------
  1720. bool CPortalRender::IsPortalViewID( view_id_t id )
  1721. {
  1722. if ( id == m_HeadPortalViewIDNode.iPrimaryViewID )
  1723. return true;
  1724. for ( int i = 0; i < MAX_PORTAL_RECURSIVE_VIEWS; ++i )
  1725. {
  1726. PortalViewIDNode_t* pNode = m_PortalViewIDNodeChain[i];
  1727. if ( pNode )
  1728. {
  1729. // recursively search child nodes, they get their own ids.
  1730. if ( Recursive_IsPortalViewID( pNode, id ) )
  1731. return true;
  1732. }
  1733. }
  1734. return false;
  1735. }