//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $Workfile: $ // $Date: $ // $NoKeywords: $ //=============================================================================// #ifndef DISPINFO_H #define DISPINFO_H #ifdef _WIN32 #pragma once #endif //============================================================================= #include #include "idispinfo.h" #include "bspfile.h" #include "mathlib/vmatrix.h" #include "dispnode.h" #include "builddisp.h" #include "utlvector.h" #include "disp_helpers.h" #include "tier0/fasttimer.h" #include "dlight.h" #include "utllinkedlist.h" #include "zone.h" struct model_t; class IMesh; class CMeshBuilder; struct ShadowInfo_t; class CDecalNodeSetupCache; class CDispInfo : public IDispInfo, public CDispUtilsHelper { // IDispInfo overrides. public: virtual ~CDispInfo(); virtual void GetIntersectingSurfaces( GetIntersectingSurfaces_Struct *pStruct ); virtual void RenderWireframeInLightmapPage( int pageId ); virtual void GetBoundingBox( Vector& bbMin, Vector& bbMax ); virtual void SetParent( SurfaceHandle_t surfID ); virtual SurfaceHandle_t GetParent(); // returns surfID // add the dlights on this surface to the lightmap buffer for updload virtual void AddDynamicLights( dlight_t *pLights, unsigned int lightMask ); // compute which dlights affect this surface virtual unsigned int ComputeDynamicLightMask( dlight_t *pLights ); virtual DispDecalHandle_t NotifyAddDecal( decal_t *pDecal, float flSize ); virtual void NotifyRemoveDecal( DispDecalHandle_t h ); virtual DispShadowHandle_t AddShadowDecal( ShadowHandle_t shadowHandle ); virtual void RemoveShadowDecal( DispShadowHandle_t handle ); // Compute shadow fragments for a particular shadow virtual bool ComputeShadowFragments( DispShadowHandle_t h, int& vertexCount, int& indexCount ); virtual bool GetTag(); virtual void SetTag(); public: //========================================================================= // // Construction/Decontruction // CDispInfo(); // Used for indexing displacements. CDispInfo* GetDispByIndex( int index ) { return index == 0xFFFF ? 0 : &m_pDispArray->m_pDispInfos[index]; } // Get this displacement's index into the main array. int GetDispIndex() { return this - m_pDispArray->m_pDispInfos; } //========================================================================= // // Flags // void SetTouched( bool bTouched ); bool IsTouched( void ); // Rendering. void ClearLOD(); void DrawDispAxes(); bool Render( CGroupMesh *pGroup, bool bAllowDebugModes ); // Add in the contribution of a dynamic light. void AddSingleDynamicLight( dlight_t& dl ); void AddSingleDynamicLightBumped( dlight_t& dl ); // Add in the contribution of a dynamic alpha light. void AddSingleDynamicAlphaLight( dlight_t& dl ); // Cast a ray against this surface bool TestRay( Ray_t const& ray, float start, float end, float& dist, Vector2D* lightmapUV, Vector2D* texureUV ); // CDispUtilsHelper implementation. public: virtual const CPowerInfo* GetPowerInfo() const; virtual CDispNeighbor* GetEdgeNeighbor( int index ); virtual CDispCornerNeighbors* GetCornerNeighbors( int index ); virtual CDispUtilsHelper* GetDispUtilsByIndex( int index ); // Initialization functions. public: // These are used to mess with indices. int VertIndex( int x, int y ) const; int VertIndex( CVertIndex const &vert ) const; CVertIndex IndexToVert( int index ) const; // Helpers to test decal intersection bit on decals. void SetNodeIntersectsDecal( CDispDecal *pDispDecal, CVertIndex const &nodeIndex ); int GetNodeIntersectsDecal( CDispDecal *pDispDecal, CVertIndex const &nodeIndex ); public: // Copy data from a ddispinfo_t. void CopyMapDispData( const ddispinfo_t *pBuildDisp ); // This is called from CreateStaticBuffers_All after the CCoreDispInfo is fully // initialized. It just copies the data that it needs. bool CopyCoreDispData( model_t *pWorld, const MaterialSystem_SortInfo_t *pSortInfos, const CCoreDispInfo *pInfo, bool bRestoring ); // called by CopyCoreDispData, just copies the vert data void CopyCoreDispVertData( const CCoreDispInfo *pInfo, float bumpSTexCoordOffset ); // Checks the SURFDRAW_BUMPLIGHT flag and returns NUM_BUMP_VECTS+1 if it's set // and 1 if not. int NumLightMaps(); // This calculates the vertex's position on the base surface. // (Same result as CCoreDisp::GetFlatVert). Vector GetFlatVert( int iVertex ); // Rendering functions. public: // Set m_BBoxMin and m_BBoxMax. Uses g_TempDispVerts and assumes m_LODs have been validated. void UpdateBoundingBox(); // Number of verts per side. int GetSideLength() const; // Return the total number of vertices. int NumVerts() const; // Figure out the vector's projection in the decal's space. void DecalProjectVert( Vector const &vPos, CDispDecalBase *pDispDecal, ShadowInfo_t const* pInfo, Vector &out ); void CullDecals( int iNodeBit, CDispDecal **decals, int nDecals, CDispDecal **childDecals, int &nChildDecals ); void TesselateDisplacement(); // Pass all the mesh data in to the material system. void SpecifyDynamicMesh(); void SpecifyWalkableDynamicMesh( void ); void SpecifyBuildableDynamicMesh( void ); // Clear all active verts except the corner verts. void InitializeActiveVerts(); // Returns a particular vertex CDispRenderVert* GetVertex( int i ); // Methods to compute lightmap coordinates, texture coordinates, // and lightmap color based on displacement u,v void ComputeLightmapAndTextureCoordinate( RayDispOutput_t const& output, Vector2D* luv, Vector2D* tuv ); // This little beastie generate decal fragments void GenerateDecalFragments( CVertIndex const &nodeIndex, int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal ); private: // Initializes node AABB tree void UpdateNodeBoundingBoxes(); void UpdateNodeBoundingBoxes_R( CVertIndex const &nodeIndex, int iNodeBitIndex, int iLevel ); // Two functions for adding decals void TestAddDecalTri( int iIndexStart, unsigned short decalHandle, CDispDecal *pDispDecal ); void TestAddDecalTri( int iIndexStart, unsigned short decalHandle, CDispShadowDecal *pDispDecal ); // Allocates fragments... CDispDecalFragment* AllocateDispDecalFragment( DispDecalHandle_t h, int nVerts = 6); // Clears decal fragment lists void ClearDecalFragments( DispDecalHandle_t h ); void ClearAllDecalFragments(); // Allocates fragments... CDispShadowFragment* AllocateShadowDecalFragment( DispShadowHandle_t h, int nCount ); // Clears shadow decal fragment lists void ClearShadowDecalFragments( DispShadowHandle_t h ); void ClearAllShadowDecalFragments(); // Used by GenerateDecalFragments void GenerateDecalFragments_R( CVertIndex const &nodeIndex, int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal, int iLevel ); // Used to create a bitfield to help cull decal tests void SetupDecalNodeIntersect( CVertIndex const &nodeIndex, int iNodeBitIndex, CDispDecalBase *pDispDecal, ShadowInfo_t const* pInfo ); // Used by SetupDecalNodeIntersect bool SetupDecalNodeIntersect_R( CVertIndex const &nodeIndex, int iNodeBitIndex, CDispDecalBase *pDispDecal, ShadowInfo_t const* pInfo, int iLevel, CDecalNodeSetupCache* pCache ); // Used for hierarchical culling of nodes against shadow frustum void FindNodesInShadowFrustum( const Frustum_t& frustum, unsigned short* pNodeArray, int* pNumNodes, int iNodeBit, int iLevel ); // Used for clipping and adding all tris in a number of nodes to a shadow decal void AddNodeTrisToDecal( CDispShadowDecal *pDispDecal, unsigned short decalHandle, unsigned short* pNodeIndices, int nNumIndices ); // Vertex/index data access. public: // bounding box Vector m_BBoxMin; Vector m_BBoxMax; int m_nIndices; // The actual # of indices being used (it can be less than m_Indices.Count() if // our LOD is reducing the triangle count). int m_iIndexOffset; // Used to get material.. CGroupMesh *m_pMesh; int m_iVertOffset; float m_BumpSTexCoordOffset; // This can be used to access the vertex data in a platform-independent way. // XBOX will get them directly out of the static vertex buffer. // PC gets them out of CDispRenderVerts. CMeshReader m_MeshReader; // List of all indices in the displacement in the current tesselation. // These indices are straight into the static buffer (ie: they're not relative // to m_iVertOffset). CUtlVector m_Indices; CUtlVector > m_Verts; // vectors that define the surface (size is NumVerts()). public: // These bits tell which vertices and nodes are currently active. // These start out the same as m_ErrorVerts but have verts added if // a neighbor needs to activate some verts. CBitVec m_ActiveVerts; // These are set to 1 if the vert is allowed to become active. // This is what takes care of different-sized neighbors. CBitVec m_AllowedVerts; int m_idLMPage; // lightmap page id SurfaceHandle_t m_ParentSurfID; // parent surfaceID int m_iPointStart; // starting point (orientation) on base face int m_iLightmapAlphaStart; int m_Contents; // surface contents public: bool m_bTouched; // touched flag int m_fSurfProp; // surface properties flag - bump-mapping, etc. int m_Power; // surface size (sides are 2^n+1). unsigned short *m_pTags; // property tags // Position and texcoordinates at the four corner points Vector m_BaseSurfacePositions[4]; Vector2D m_BaseSurfaceTexCoords[4]; // Precalculated data for displacements of this size. const CPowerInfo *m_pPowerInfo; // Neighbor info for each side, indexed by NEIGHBOREDGE_ enums. // First 4 are edge neighbors, the rest are corners. CDispNeighbor m_EdgeNeighbors[4]; CDispCornerNeighbors m_CornerNeighbors[4]; // Copied from the ddispinfo. Speciifes where in g_DispLightmapSamplePositions the (compressed) // lightmap sample positions start. int m_iLightmapSamplePositionStart; // The current triangulation for visualizing tag data. int m_nWalkIndexCount; unsigned short *m_pWalkIndices; int m_nBuildIndexCount; unsigned short *m_pBuildIndices; // This here's a bunch of per-node information DispNodeInfo_t *m_pNodeInfo; // Where the viewer was when we last tesselated. // When the viewer moves out of the sphere, UpdateLOD is called. Vector m_ViewerSphereCenter; // Used to make sure it doesn't activate verts in the wrong dispinfos. bool m_bInUse; // Decals + Shadow decals DispDecalHandle_t m_FirstDecal; DispShadowHandle_t m_FirstShadowDecal; unsigned short m_Index; // helps in debugging // Current tag value. unsigned short m_Tag; CDispArray *m_pDispArray; }; extern int g_nDispTris; extern CCycleCount g_DispRenderTime; extern bool DispInfoRenderDebugModes(); // --------------------------------------------------------------------------------- // // CDispInfo functions. // --------------------------------------------------------------------------------- // inline int CDispInfo::GetSideLength() const { return m_pPowerInfo->m_SideLength; } inline int CDispInfo::NumVerts() const { Assert( m_Verts.Count() == m_pPowerInfo->m_MaxVerts ); return m_pPowerInfo->m_MaxVerts; } //----------------------------------------------------------------------------- // Returns a particular vertex //----------------------------------------------------------------------------- inline CDispRenderVert* CDispInfo::GetVertex( int i ) { Assert( i < NumVerts() ); return &m_Verts[i]; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- inline void CDispInfo::SetTouched( bool bTouched ) { m_bTouched = bTouched; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- inline bool CDispInfo::IsTouched( void ) { return m_bTouched; } inline int CDispInfo::VertIndex( int x, int y ) const { Assert( x >= 0 && x < GetSideLength() && y >= 0 && y < GetSideLength() ); return y * GetSideLength() + x; } inline int CDispInfo::VertIndex( CVertIndex const &vert ) const { Assert( vert.x >= 0 && vert.x < GetSideLength() && vert.y >= 0 && vert.y < GetSideLength() ); return vert.y * GetSideLength() + vert.x; } void DispInfo_BatchDecals( CDispInfo **pVisibleDisps, int nVisibleDisps ); void DispInfo_DrawDecals( class IMatRenderContext *pRenderContex, CDispInfo **pVisibleDisps, int nVisibleDisps ); #endif // DISPINFO_H