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

333 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #ifndef PORTALRENDER_H
  8. #define PORTALRENDER_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "iviewrender.h"
  13. #include "view_shared.h"
  14. #include "viewrender.h"
  15. #define MAX_PORTAL_RECURSIVE_VIEWS 11 //maximum number of recursions we allow when drawing views through portals. Seeing as how 5 is extremely choppy under best conditions and is barely visible, 10 is a safe limit. Adding one because 0 tends to be the primary view in most arrays of this size
  16. class CPortalRenderable
  17. {
  18. public:
  19. CPortalRenderable( void );
  20. virtual ~CPortalRenderable( void );
  21. //----------------------------------------------------------------------------
  22. //Stencil-based drawing helpers, these are ONLY used in stencil drawing mode
  23. //----------------------------------------------------------------------------
  24. virtual void DrawPreStencilMask( void ) { }; //Do whatever drawing you need before cutting the stencil hole
  25. virtual void DrawStencilMask( void ) { }; //Draw to wherever you should see through the portal. The mask will later be filled with the portal view.
  26. virtual void DrawPostStencilFixes( void ) { }; //After done drawing to the portal mask, we need to fix the depth buffer as well as fog. So draw your mesh again, writing to z and with the fog color alpha'd in by distance
  27. //----------------------------------------------------------------------------
  28. //Rendering of views beyond the portal
  29. //----------------------------------------------------------------------------
  30. virtual void RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView ) { };
  31. virtual void RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView ) { };
  32. //----------------------------------------------------------------------------
  33. //Visibility through portals
  34. //----------------------------------------------------------------------------
  35. virtual bool DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const { return false; };
  36. virtual SkyboxVisibility_t SkyBoxVisibleFromPortal( void ) { return SKYBOX_NOT_VISIBLE; };
  37. //-----------------------------------------------------------------------------
  38. //Fog workarounds
  39. //-----------------------------------------------------------------------------
  40. virtual const Vector& GetFogOrigin( void ) const { return vec3_origin; };
  41. virtual void ShiftFogForExitPortalView() const;
  42. //-----------------------------------------------------------------------------
  43. //Portal visibility testing
  44. //-----------------------------------------------------------------------------
  45. //Based on view, will the camera be able to see through the portal this frame? This will allow the stencil mask to start being tested for pixel visibility.
  46. virtual bool ShouldUpdatePortalView_BasedOnView( const CViewSetup &currentView, CUtlVector<VPlane> &currentComplexFrustum ) { return false; };
  47. //Stencil mode only: You stated the portal was visible based on view, and this is how much of the screen your stencil mask took up last frame. Still want to draw this frame? Values less than zero indicate a lack of data from last frame
  48. virtual bool ShouldUpdatePortalView_BasedOnPixelVisibility( float fScreenFilledByStencilMaskLastFrame_Normalized ) { return (fScreenFilledByStencilMaskLastFrame_Normalized != 0.0f); }; // < 0 is unknown visibility, > 0 is known to be partially visible
  49. //-----------------------------------------------------------------------------
  50. // Misc
  51. //-----------------------------------------------------------------------------
  52. virtual CPortalRenderable* GetLinkedPortal() const { return NULL; };
  53. const VMatrix& MatrixThisToLinked() const;
  54. virtual bool ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup ) { return false; };
  55. virtual void DrawPortal( void ) { }; //sort of like what you'd expect to happen in C_BaseAnimating::DrawModel() if portals were fully compatible with models
  56. virtual C_BaseEntity *PortalRenderable_GetPairedEntity( void ) { return NULL; }; //Pairing a portal with an entity is common but not required. Accessing that entity allows the CPortalRender system to better optimize.
  57. VMatrix m_matrixThisToLinked; //Always going to need a matrix
  58. //-----------------------------------------------------------------------------
  59. //SFM related
  60. //-----------------------------------------------------------------------------
  61. bool m_bIsPlaybackPortal;
  62. virtual void GetToolRecordingState( bool bActive, KeyValues *msg ) { };
  63. virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues ) { };
  64. protected:
  65. //-----------------------------------------------------------------------------
  66. // Wrap the draw of the surface that makes use of your portal render targets with these. Only required for texture mode, but won't hurt stencil mode.
  67. // Using these will allow you to know whether it's worth drawing the other side of a portal next frame.
  68. //-----------------------------------------------------------------------------
  69. void BeginPortalPixelVisibilityQuery( void );
  70. void EndPortalPixelVisibilityQuery( void );
  71. CPortalRenderable *FindRecordedPortal( int nPortalId ); //routed through here to get friend access to CPortalRender
  72. //routed through here to get friend access to CViewRender
  73. void CopyToCurrentView( CViewRender *pViewRender, const CViewSetup &viewSetup );
  74. void ViewDrawScene_PortalStencil( CViewRender *pViewRender, const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility );
  75. void Draw3dSkyboxworld_Portal( CViewRender *pViewRender, const CViewSetup &viewIn, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget = NULL );
  76. void ViewDrawScene( CViewRender *pViewRender, bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &viewIn, int nClearFlags, view_id_t viewID, bool bDrawViewModel = false, int baseDrawFlags = 0, ViewCustomVisibility_t *pCustomVisibility = NULL );
  77. void SetViewRecursionLevel( int iViewRecursionLevel );
  78. void SetRemainingViewDepth( int iRemainingViewDepth );
  79. void SetViewEntranceAndExitPortals( CPortalRenderable *pEntryPortal, CPortalRenderable *pExitPortal );
  80. private:
  81. int m_iPortalViewIDNodeIndex; //each PortalViewIDNode_t has a child node link for each CPortalRenderable in CPortalRender::m_ActivePortals. This portal follows the same indexed link from each node
  82. friend class CPortalRender;
  83. };
  84. //-----------------------------------------------------------------------------
  85. // inline state querying methods
  86. //-----------------------------------------------------------------------------
  87. inline const VMatrix& CPortalRenderable::MatrixThisToLinked() const
  88. {
  89. return m_matrixThisToLinked;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Portal rendering materials
  93. //-----------------------------------------------------------------------------
  94. struct PortalRenderingMaterials_t
  95. {
  96. CMaterialReference m_Wireframe;
  97. CMaterialReference m_WriteZ_Model;
  98. CMaterialReference m_TranslucentVertexColor;
  99. };
  100. typedef CPortalRenderable *(*PortalRenderableCreationFunc)( void );
  101. struct PortalRenderableCreationFunction_t
  102. {
  103. CUtlString portalType;
  104. PortalRenderableCreationFunc creationFunc;
  105. };
  106. struct PortalViewIDNode_t
  107. {
  108. CUtlVector<PortalViewIDNode_t *> ChildNodes; //links will only be non-null if they're useful (can see through the portal at that depth and view setup)
  109. int iPrimaryViewID;
  110. //skybox view id is always primary + 1
  111. //In stencil mode this wraps CPortalRenderable::DrawStencilMask() and gives previous frames' results to CPortalRenderable::RenderPortalViewToBackBuffer()
  112. //In texture mode there's no good spot to auto-wrap occlusion tests. So you'll need to wrap it yourself for that.
  113. OcclusionQueryObjectHandle_t occlusionQueryHandle;
  114. int iWindowPixelsAtQueryTime;
  115. int iOcclusionQueryPixelsRendered;
  116. float fScreenFilledByPortalSurfaceLastFrame_Normalized;
  117. };
  118. //-----------------------------------------------------------------------------
  119. // Portal rendering management class
  120. //-----------------------------------------------------------------------------
  121. class CPortalRender : public CAutoGameSystem
  122. {
  123. public:
  124. CPortalRender();
  125. // Inherited from IGameSystem
  126. virtual void LevelInitPreEntity();
  127. virtual void LevelShutdownPreEntity();
  128. // Are we currently rendering a portal?
  129. bool IsRenderingPortal() const;
  130. // Returns the current View IDs. Portal View IDs will change often (especially with recursive views) and should not be cached
  131. int GetCurrentViewId() const;
  132. int GetCurrentSkyboxViewId() const;
  133. // Returns view recursion level
  134. int GetViewRecursionLevel() const;
  135. float GetPixelVisilityForPortalSurface( const CPortalRenderable *pPortal ) const; //normalized for how many of the screen's possible pixels it takes up, less than zero indicates a lack of data from last frame
  136. // Returns the remaining number of portals to render within other portals
  137. // lets portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
  138. int GetRemainingPortalViewDepth() const;
  139. inline CPortalRenderable *GetCurrentViewEntryPortal( void ) const { return m_pRenderingViewForPortal; }; //if rendering a portal view, this is the portal the current view enters into
  140. inline CPortalRenderable *GetCurrentViewExitPortal( void ) const { return m_pRenderingViewExitPortal; }; //if rendering a portal view, this is the portal the current view exits from
  141. // true if the rendering path for portals uses stencils instead of textures
  142. bool ShouldUseStencilsToRenderPortals() const;
  143. //it's a good idea to force cheaper water when the ratio of performance gain to noticability is high
  144. //0 = force no reflection/refraction
  145. //1/2 = downgrade to simple/world reflections as seen in advanced video options
  146. //3 = no downgrade
  147. int ShouldForceCheaperWaterLevel() const;
  148. bool ShouldObeyStencilForClears() const;
  149. //sometimes we have to tweak some systems to render water properly with portals
  150. void WaterRenderingHandler_PreReflection() const;
  151. void WaterRenderingHandler_PostReflection() const;
  152. void WaterRenderingHandler_PreRefraction() const;
  153. void WaterRenderingHandler_PostRefraction() const;
  154. // return value indicates that something was done, and render lists should be rebuilt afterwards
  155. bool DrawPortalsUsingStencils( CViewRender *pViewRender );
  156. void DrawPortalsToTextures( CViewRender *pViewRender, const CViewSetup &cameraView ); //updates portal textures
  157. void OverlayPortalRenderTargets( float w, float h );
  158. void UpdateDepthDoublerTexture( const CViewSetup &viewSetup ); //our chance to update all depth doubler texture before the view model is added to the back buffer
  159. void EnteredPortal( CPortalRenderable *pEnteredPortal ); //does a bit of internal maintenance whenever the player/camera has logically passed the portal threshold
  160. // adds, removes a portal to the set of renderable portals
  161. void AddPortal( CPortalRenderable *pPortal );
  162. void RemovePortal( CPortalRenderable *pPortal );
  163. // Methods to query about the exit portal associated with the currently rendering portal
  164. void ShiftFogForExitPortalView() const;
  165. const Vector &GetExitPortalFogOrigin() const;
  166. SkyboxVisibility_t IsSkyboxVisibleFromExitPortal() const;
  167. bool DoesExitPortalViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const;
  168. void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
  169. CPortalRenderable* FindRecordedPortal( IClientRenderable *pRenderable );
  170. void AddPortalCreationFunc( const char *szPortalType, PortalRenderableCreationFunc creationFunc );
  171. CViewSetup m_RecursiveViewSetups[MAX_PORTAL_RECURSIVE_VIEWS]; //before we recurse into a view, we backup the view setup here for reference
  172. // tests if the parameter ID is being used by portal pixel vis queries
  173. bool IsPortalViewID( view_id_t id );
  174. private:
  175. struct RecordedPortalInfo_t
  176. {
  177. CPortalRenderable *m_pActivePortal;
  178. int m_nPortalId;
  179. IClientRenderable *m_pPlaybackRenderable;
  180. };
  181. PortalViewIDNode_t m_HeadPortalViewIDNode; //pseudo node. Primary view id will be VIEW_MAIN. The child links are what we really care about
  182. PortalViewIDNode_t* m_PortalViewIDNodeChain[MAX_PORTAL_RECURSIVE_VIEWS]; //the view id node chain we're following, 0 always being &m_HeadPortalViewIDNode (offsetting by 1 seems like it'd cause bugs in the long run)
  183. void UpdatePortalPixelVisibility( void ); //updates pixel visibility for portal surfaces
  184. // Handles a portal update message
  185. void HandlePortalUpdateMessage( KeyValues *pKeyValues );
  186. // Finds a recorded portal
  187. int FindRecordedPortalIndex( int nPortalId );
  188. CPortalRenderable* FindRecordedPortal( int nPortalId );
  189. CUtlVector<PortalRenderableCreationFunction_t> m_PortalRenderableCreators; //for SFM compatibility
  190. private:
  191. PortalRenderingMaterials_t m_Materials;
  192. int m_iViewRecursionLevel;
  193. int m_iRemainingPortalViewDepth; //let's portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
  194. CPortalRenderable *m_pRenderingViewForPortal; //the specific pointer for the portal that we're rending a view for
  195. CPortalRenderable *m_pRenderingViewExitPortal; //the specific pointer for the portal that our view exits from
  196. CUtlVector<CPortalRenderable *> m_AllPortals; //All portals currently in memory, active or not
  197. CUtlVector<CPortalRenderable *> m_ActivePortals;
  198. CUtlVector< RecordedPortalInfo_t > m_RecordedPortals;
  199. public:
  200. //frustums with more (or less) than 6 planes. Store each recursion level's custom frustum here so further recursions can be better optimized.
  201. //When going into further recursions, if you've failed to fill in a complex frustum, the standard frustum will be copied in.
  202. //So all parent levels are guaranteed to contain valid data
  203. CUtlVector<VPlane> m_RecursiveViewComplexFrustums[MAX_PORTAL_RECURSIVE_VIEWS];
  204. const PortalRenderingMaterials_t& m_MaterialsAccess;
  205. friend class CPortalRenderable;
  206. friend void OnRenderStart();
  207. };
  208. extern CPortalRender* g_pPortalRender;
  209. inline CPortalRenderable *CPortalRenderable::FindRecordedPortal( int nPortalId )
  210. {
  211. return g_pPortalRender->FindRecordedPortal( nPortalId );
  212. }
  213. class CPortalRenderableCreator //create one of these as a global and ensure you register exactly once
  214. {
  215. public:
  216. CPortalRenderableCreator( const char *szPortalType, PortalRenderableCreationFunc creationFunction )
  217. {
  218. g_pPortalRender->AddPortalCreationFunc( szPortalType, creationFunction );
  219. }
  220. };
  221. //-----------------------------------------------------------------------------
  222. // inline friend access redirects
  223. //-----------------------------------------------------------------------------
  224. inline void CPortalRenderable::CopyToCurrentView( CViewRender *pViewRender, const CViewSetup &viewSetup )
  225. {
  226. pViewRender->m_CurrentView = viewSetup;
  227. }
  228. inline void CPortalRenderable::ViewDrawScene_PortalStencil( CViewRender *pViewRender, const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility )
  229. {
  230. pViewRender->ViewDrawScene_PortalStencil( viewIn, pCustomVisibility );
  231. }
  232. inline void CPortalRenderable::Draw3dSkyboxworld_Portal( CViewRender *pViewRender, const CViewSetup &viewIn, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget )
  233. {
  234. pViewRender->Draw3dSkyboxworld_Portal( viewIn, nClearFlags, bDrew3dSkybox, nSkyboxVisible, pRenderTarget );
  235. }
  236. inline void CPortalRenderable::ViewDrawScene( CViewRender *pViewRender, bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &viewIn, int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags, ViewCustomVisibility_t *pCustomVisibility )
  237. {
  238. pViewRender->ViewDrawScene( bDrew3dSkybox, nSkyboxVisible, viewIn, nClearFlags, viewID, bDrawViewModel, baseDrawFlags, pCustomVisibility );
  239. }
  240. inline void CPortalRenderable::SetViewRecursionLevel( int iViewRecursionLevel )
  241. {
  242. g_pPortalRender->m_iViewRecursionLevel = iViewRecursionLevel;
  243. }
  244. inline void CPortalRenderable::SetRemainingViewDepth( int iRemainingViewDepth )
  245. {
  246. g_pPortalRender->m_iRemainingPortalViewDepth = iRemainingViewDepth;
  247. }
  248. inline void CPortalRenderable::SetViewEntranceAndExitPortals( CPortalRenderable *pEntryPortal, CPortalRenderable *pExitPortal )
  249. {
  250. g_pPortalRender->m_pRenderingViewForPortal = pEntryPortal;
  251. g_pPortalRender->m_pRenderingViewExitPortal = pExitPortal;
  252. }
  253. #endif //#ifndef PORTALRENDER_H