//============ Copyright (c) Valve Corporation, All rights reserved. ============ // // Class to represent and write out a BSP file. // //=============================================================================== #ifndef SIMPLEBSPFILE_H #define SIMPLEBSPFILE_H #if defined( COMPILER_MSVC ) #pragma once #endif #include "bitvec.h" #include "simplemapfile.h" #include "vbspmathutil.h" class CSimpleMapFile; struct MapEntity_t; //----------------------------------------------------------------------------- // Indicates that the BSP node is a leaf (m_pChildren will be all NULL) //----------------------------------------------------------------------------- static const int LEAF_PLANE_INDEX = -1; //----------------------------------------------------------------------------- // A sentinel cluster index used to indicate that a node does not // belong to any cluster. //----------------------------------------------------------------------------- static const int INVALID_CLUSTER_INDEX = -1; //----------------------------------------------------------------------------- // Default maximum visibility radius used to compute cluster-to-cluster // visibility. //----------------------------------------------------------------------------- static const float DEFAULT_VISIBILITY_RADIUS = 2500.0f; class CBSPBrush; class CBSPFace; class CBSPPortal; //----------------------------------------------------------------------------- // A node in a BSP tree. //----------------------------------------------------------------------------- class CBSPNode { public: CBSPNode(); ~CBSPNode(); bool IsLeaf() const { return m_nSplitPlaneIndex == LEAF_PLANE_INDEX; } CBSPNode *m_pParent; CBSPNode *m_pChildren[2]; // If this node is a leaf, the value is LEAF_PLANE_INDEX. // Otherwise, the split plane is always the "positive" plane of a pair (that is, even numbered). int m_nSplitPlaneIndex; // Flags indicating the contents of the BSP node. MapBrushContentsFlags_t m_ContentsFlags; // This field owns the contents' memory CUtlVector< CBSPBrush * > m_ClippedBrushes; // A list of portal faces or detail faces on this node. // Leaf nodes may contain only detail faces, non-leaf nodes may contain only portal faces. // This field does NOT own the contents' memory; the faces are owned by the containing model or the portal // (depending on what kind of face it is). CUtlVector< CBSPFace * > m_Faces; // This field does NOT own the contents' memory; the portals are owned by the containing model. CUtlVector< CBSPPortal * > m_Portals; // AABB around the node Vector m_vMinBounds, m_vMaxBounds; // True if an entity can reach this node via portals, False if unreachable bool m_bEntityCanReach; // The BSP cluster to which this leaf node belongs (only applies to the world BSP tree). // A cluster is simply a group of leaves which share visibility information. // In practice, there is 1 cluster per non-solid world leaf. // This value is ignored for non-leaf nodes. int m_nClusterIndex; private: // Disallow value semantics CBSPNode( const CBSPNode &other ); CBSPNode &operator=( const CBSPNode &other ); }; //----------------------------------------------------------------------------- // A binary space partition tree. //----------------------------------------------------------------------------- class CBSPTree { public: CBSPTree(); ~CBSPTree(); CBSPNode *m_pRoot; CBSPNode m_OutsideNode; // a sentinel node which exists in the space outside of the BSP tree // AABB around the tree Vector m_vMinBounds, m_vMaxBounds; private: // Disallow value semantics CBSPTree( const CBSPTree &other ); CBSPTree &operator=( const CBSPTree &other ); }; //----------------------------------------------------------------------------- // A portal between two nodes of a BSP tree. //----------------------------------------------------------------------------- class CBSPPortal { public: //----------------------------------------------------------------------------- // Constructs a default, null portal. //----------------------------------------------------------------------------- CBSPPortal(); //----------------------------------------------------------------------------- // Constructs a new portal along the same plane as the given portal, // except with a different shape. // This is used when a single portal is cut by a node's splitting plane // into two new portals along the same plane. // // This constructor swaps its polygon's points with the given polygon's // for efficiency! //----------------------------------------------------------------------------- CBSPPortal( const CBSPPortal &other, Polygon_t *pPortalShape ); ~CBSPPortal(); CBSPNode *GetOtherNode( const CBSPNode *pNode ) const; //----------------------------------------------------------------------------- // Returns either 0 or 1 to indicate which node attached to this portal // is responsible for drawing the face. // This call is only valid if m_PortalFaces.Count() > 0. //----------------------------------------------------------------------------- int GetNodeIndexForFace() const; // The nodes on either side of the portal. // The convention is that the plane of the portal faces in the direction from node 1 towards node 0. // (That is, node 0 is in the positive half-space of the plane while node 1 is in the the negative half-space). // In a properly built tree, these nodes are always leaves (during construction they may // point to interior nodes). CBSPNode *m_pNodes[2]; // Not NULL if this portal lives on a node's split plane (which is usually the case, except for // portals at the edge of the world). This node is never a leaf. CBSPNode *m_pOnNode; // Shape of the portal. Polygon_t m_Polygon; // Plane along which the portal lives. Plane_t m_Plane; // These are the faces generated when the portal is in-between solid and non-solid contents. // Logically, there is only 1 convex face, but some constraints (e.g. max lightmap size per face) // can require subdivision of faces. // This class owns the faces and frees them on destruction. CUtlVector< CBSPFace * > m_PortalFaces; private: // Disallow value semantics CBSPPortal( const CBSPPortal &other ); CBSPPortal &operator=( const CBSPPortal &other ); }; //----------------------------------------------------------------------------- // The side of a BSP brush (convex solid). // This class is copyable. //----------------------------------------------------------------------------- class CBSPBrushSide { public: //----------------------------------------------------------------------------- // Constructs a default, invalid brush side. //----------------------------------------------------------------------------- CBSPBrushSide(); //----------------------------------------------------------------------------- // Constructs a new brush side initialized from map data. //----------------------------------------------------------------------------- CBSPBrushSide( const MapBrushSide_t *pMapBrushSide ); // Index into BSP creation context's plane list int m_nPlaneIndex; // Index into map's texture infos array int m_nTextureInfoIndex; MapBrushSideSurfaceFlags_t m_SurfaceFlags; Polygon_t m_Polygon; }; //----------------------------------------------------------------------------- // A convex solid in a BSP file, produced from CSG operations on brushes // found in the original map. // This class is copyable. //----------------------------------------------------------------------------- class CBSPBrush { public: //----------------------------------------------------------------------------- // Constructs a default brush solid with no sides. //----------------------------------------------------------------------------- CBSPBrush(); //----------------------------------------------------------------------------- // Constructs a new default brush solid initialized from map data. //----------------------------------------------------------------------------- CBSPBrush( const MapBrush_t *pMapBrush, const MapBrushSide_t *pMapBrushSides ); Vector m_vMinBounds, m_vMaxBounds; CCopyableUtlVector< CBSPBrushSide > m_Sides; MapBrushContentsFlags_t m_ContentsFlags; const MapBrush_t *m_pOriginalBrush; // Which side of the node splitting plane this brush is on. // (both values only used during BSP construction in order to split nodes). PlaneSide_t m_nTempSplitSide; PlaneSide_t m_nSplitSide; }; //----------------------------------------------------------------------------- // A renderable face associated with the side of a detail brush or a portal. // This class is copyable. //----------------------------------------------------------------------------- class CBSPFace { public: //----------------------------------------------------------------------------- // Constructs a default, empty face. //----------------------------------------------------------------------------- CBSPFace(); //----------------------------------------------------------------------------- // Constructs a face from the side of a BSP brush solid. //----------------------------------------------------------------------------- CBSPFace( const CBSPBrush *pBrush, const CBSPBrushSide *pSide ); //----------------------------------------------------------------------------- // Constructs a face from another face, except with a different shape. // Useful when cutting a face into parts. // // This constructor swaps its polygon's points with the given polygon's // for efficiency. //----------------------------------------------------------------------------- CBSPFace( const CBSPFace &other, Polygon_t *pPolygon ); // Index into map's texture infos array int m_nTextureInfoIndex; // Index into BSP creation context's plane list int m_nPlaneIndex; Polygon_t m_Polygon; // Index into the map's displacement array, if this face comes from a displacement surface. int m_nDisplacementIndex; // The index of this face in the final output. // All faces in a BSP file appear sequentially by model. // Within a model's contiguous list of faces, portal faces are serialized first // via depth-first traversal of the BSP tree, followed by detail faces. int m_nSerializedFaceIndex; }; //----------------------------------------------------------------------------- // An entity in a map with associated CSG brush data. // The 0th model in a BSP file corresponds to the world entity of the map // and includes all detail brushes from detail entities in the original map. //----------------------------------------------------------------------------- class CBSPModel { public: CBSPModel(); ~CBSPModel(); CBSPTree *m_pTree; // Detail faces are owned by the model and are freed on destruction. CUtlVector< CBSPFace * > m_DetailFaces; // Portals are owned by the model and are freed on destruction. CUtlVector< CBSPPortal * > m_Portals; Vector m_vMinBounds, m_vMaxBounds; private: // Disallow value semantics CBSPModel( const CBSPModel &other ); CBSPModel &operator=( const CBSPModel &other ); }; //----------------------------------------------------------------------------- // In theory, a cluster is a set of BSP leaf nodes. // In practice, it is simply a pointer to a single, existing BSP leaf node. //----------------------------------------------------------------------------- struct BSPCluster_t { const CBSPNode *m_pLeafNode; }; //----------------------------------------------------------------------------- // An in-memory representation of a BSP file, built from a map file. // This class requires that the map file remain valid for its lifetime, // though the map file is accessed in a read-only manner. //----------------------------------------------------------------------------- class CSimpleBSPFile { public: CSimpleBSPFile(); ~CSimpleBSPFile(); const CSimpleMapFile *GetOriginalMap() const { return m_pMapFile; } const CPlaneHash *GetPlaneHash() const { return &m_PlaneHash; } const CBSPModel * const *GetModels() const { return m_Models.Base(); } int GetModelCount() const { return m_Models.Count(); } const CBSPFace * GetDisplacementFaces() const { return m_DisplacementFaces.Base(); } int GetDisplacementFaceCount() const { return m_DisplacementFaces.Count(); } void SetVisibilityRadius( float flRadius ) { m_flVisibilityRadius = flRadius; } int GetClusterCount() const { return m_Clusters.Count(); } const byte * GetVisibilityData() const { return m_VisibilityData.Base(); } //----------------------------------------------------------------------------- // Populates this in-memory BSP file object from the given in-memory map file. //----------------------------------------------------------------------------- void CreateFromMapFile( const CSimpleMapFile *pMapFile ); private: // Source map file; must remain valid for the lifetime of this object. const CSimpleMapFile *m_pMapFile; // Array of planes with acceleration structure for fast lookup. // Starts off copied from the map (so all map plane indices are valid) but is expanded // during the BSP process via CSG operations. CPlaneHash m_PlaneHash; CUtlVector< CBSPModel * > m_Models; CUtlVector< CBSPFace > m_DisplacementFaces; CUtlVector< BSPCluster_t > m_Clusters; CUtlVector< byte > m_VisibilityData; // A monotonically increasing value which increments for every face generated during the BSP construction process. int m_nNextFaceIndex; // The radius value beyond which clusters cannot see each other. float m_flVisibilityRadius; void ProcessWorldEntity( const MapEntity_t *pMapEntity ); void ProcessEntity( const MapEntity_t *pMapEntity ); CBSPNode *GenerateBSPGrid( int nMinX, int nMinY, int nMaxX, int nMaxY, int nAbsoluteMins[2], int nAbsoluteMaxs[2], CBSPNode **ppNodeList ); CBSPNode *CreateGridNode( int nX, int nY ); void CreateBSPBrushList( const MapBrush_t *pBrushes, int nBrushCount, bool bIncludeDetail, bool bIncludeStructural, const Vector &vClipMin, const Vector &vClipMax, CUtlVector< CBSPBrush * > *pBrushList ); CBSPBrush *CreateClippedBrush( const MapBrush_t *pMapBrush, const Vector &vClipMin, const Vector &vClipMax, int nClipMinPlanes[2], int nClipMaxPlanes[2] ); void SplitBrush( CBSPBrush *pBrush, int nPlaneIndex, CBSPBrush **ppFrontBrush, CBSPBrush **ppBackBrush ); PlaneSide_t GetPrimaryPlaneSide( CBSPBrush *pBrush, Plane_t *pPlane ); CBSPTree *BuildBSPTree( CUtlVector< CBSPBrush * > *pBrushList, const Vector &vMin, const Vector &vMax ); void BuildBSPChildren( CBSPNode *pNode, CUtlVector< CBSPBrush * > *pBrushList ); int FindBestSplitPlane( CUtlVector< CBSPBrush * > *pBrushList ); void MakeBrushPolygons( CBSPBrush *pBrush ); void SplitBrushList( CUtlVector< CBSPBrush * > *pBrushList, CBSPNode *pNode, CUtlVector< CBSPBrush * > *pFrontChildList, CUtlVector< CBSPBrush * > *pBackChildList ); PlaneSide_t TestBrushAgainstPlaneIndex( CBSPBrush *pBrush, int nPlaneIndex, int *nNumSplits ); void PruneNodes( CBSPNode *pNode, CUtlVector< CBSPPortal * > *pPortalList ); void BuildTreePortals( CBSPTree *pTree, CUtlVector< CBSPPortal * > *pPortalList ); void BuildNodePortals( CBSPNode *pNode, CUtlVector< CBSPPortal * > *pPortalList ); void FloodEntities( CBSPTree *pTree ); void FloodEntity( CBSPNode *pNode, const Vector &vPosition ); void FloodFillThroughPortals( CBSPNode *pNode ); void MakeUnreachableNodesSolid( CBSPNode *pNode ); void MakeFacesFromPortals( CBSPModel *pModel ); void NumberPortalFaces( CBSPNode *pNode ); void BuildRadialVisibilityData( CBSPNode *pRootNode ); void AssignClusterIndicesToLeaves( CBSPNode *pNode ); void CreateDisplacementFaces(); void PopulateTreeWithDetail( const CBSPTree *pTree, int nFirstBrush, int nNumBrushes, CUtlVector< CBSPFace * > *pDetailFaceList ); void FilterFaceIntoTree( CBSPNode *pNode, CBSPFace *pClippedFace, CBSPFace *pOriginalFace ); void FilterBrushIntoTree( CBSPNode *pNode, CBSPBrush *pBrush ); }; //----------------------------------------------------------------------------- // Dumps useful information about the BSP to several files beginning // with the path string pPrefixName and suffixed appropriately // (e.g. "_ent.txt", "_bsp.csv", "_tex.csv"). //----------------------------------------------------------------------------- void DumpBSPInfo( const char *pPrefixName, byte *pBSPData, int nBSPDataSize ); //----------------------------------------------------------------------------- // Writes all faces to a .gl file which can be viewed in GLView. //----------------------------------------------------------------------------- void WriteGLBSPFile( FileHandle_t fileHandle, byte *pBSPData, int nBSPDataSize ); //----------------------------------------------------------------------------- // Dumps the contents of the given lump to the specified file. //----------------------------------------------------------------------------- void DumpLump( FileHandle_t fileHandle, byte *pBSPData, int nBSPDataSize, int nLumpIndex ); #endif // SIMPLEBSPFILE_H