This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

View File

@@ -0,0 +1,74 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Classes to aid in transferring lightmap data (luxels) between BSPs.
//
//===============================================================================
#ifndef LIGHTMAPTRANSFER_H
#define LIGHTMAPTRANSFER_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "utlvector.h"
#include "mathlib/vector.h"
#include "mathlib/intvector3d.h"
#include "bspfile.h"
class CMemoryBSPFile;
//-----------------------------------------------------------------------------
// A class which acts as a spatial hash for lightmap values.
// Multiple source files can be processed into the hash such that every single
// lightmap sample has its own entry in the hash.
// This data can then be copied into the lightmap lump of a given BSP file.
//-----------------------------------------------------------------------------
class CLuxelHash
{
public:
CLuxelHash( int nHashBucketCount );
//-----------------------------------------------------------------------------
// Adds all of the luxels in the source BSP file to a spatial hash.
// vOffset is the world-space translation to add to all coordinates in the
// source BSP file.
//-----------------------------------------------------------------------------
void AddSourceBSPFile( const CMemoryBSPFile *pSourceBSPFile, const Vector &vOffset );
//-----------------------------------------------------------------------------
// Copies lighting from the luxel hash into the target BSP file.
// Values which are not found are initialized to black.
//-----------------------------------------------------------------------------
void CopyLighting( CMemoryBSPFile *pTargetBSPFile ) const;
private:
// nDataLength is the number of ColorRGBExp32 (4 bytes each) per luxel.
// This is typically 1 for lightmaps without bump light information, or 4 for those with.
void AddLuxel( const Vector &vPosition, const Vector &vNormal, const ColorRGBExp32 *pLuxelData, int nDataLength );
bool FindLuxel( const Vector &vPosition, const Vector &vNormal, const ColorRGBExp32 **ppLuxelData, int *pDataLength ) const;
void CopyFaceLighting( CMemoryBSPFile *pTargetBSPFile, int nFace ) const;
void CopyWorldLights( CMemoryBSPFile *pTargetBSPFile ) const;
// Hashes the position and returns a hash bucket index in the range [ 0, m_HashEntries.Count() )
int GetGridEntry( const IntVector3D &vIntegerPosition ) const;
struct LuxelHashEntry_t
{
Vector m_vPosition;
Vector m_vNormal;
int m_nDataStart;
int m_nDataLength;
int m_nNextEntryIndex;
};
CUtlVector< ColorRGBExp32 > m_LuxelData; // Contiguous luxel data
CUtlVector< LuxelHashEntry_t > m_HashEntries; // Pool of hash entry linked list nodes, one per luxel
CUtlVector< dworldlight_t > m_WorldLightsLDR;
CUtlVector< dworldlight_t > m_WorldLightsHDR;
CUtlVector< int > m_UniformGrid; // 3D grid of indices into a linked list of LuxelHashEntry_t (-1 means no entry)
};
#endif // LIGHTMAPTRANSFER_H

View File

@@ -0,0 +1,236 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Class to represent and read/write a BSP file.
//
//===============================================================================
#ifndef SERIALIZESIMPLEBSPFILE_H
#define SERIALIZESIMPLEBSPFILE_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "utlvector.h"
#include "bspfile.h"
#include "gamebspfile.h"
#include "builddisp.h"
#include "vbspmathutil.h"
#include "simplemapfile.h"
class CSimpleBSPFile;
class CBSPNode;
class CBSPFace;
class CPhysCollisionEntry;
class IPhysicsCollision;
class IPhysicsSurfaceProps;
class CUtlBuffer;
//-----------------------------------------------------------------------------
// Serializes a BSP file to a provided buffer.
//-----------------------------------------------------------------------------
void SaveToFile( CUtlBuffer *pOutputBuffer, const CSimpleBSPFile *pBSPFile );
//-----------------------------------------------------------------------------
// Class to build and manipulate a BSP file in its on-disk representation.
//
// This is a lower-level representation of a BSP than CSimpleBSPFile.
//
// Can be used in one of several modes:
//
// 1) Serializing a .bsp file -
//
// a) Given the expanded, in-memory representation
// of a compiled map (CSimpleBSPFile), this class will build
// intermediate representations of various structures where needed and
// serialize the data to a .bsp file. It can be operated in a "memory
// efficient" mode where lumps are written out and freed as soon as
// possible.
//
// b) This class can also serialize a BSP file that was constructed
// in memory or previously deserialized.
//
// 2) Deserializing a .bsp file - the recognized lump types will be loaded
// and stored in memory, at which point they can be manipulated
// as needed.
// WARNING: only recognized lumps will be deserialized; this file
// has incomplete support for many lump types.
//
//-----------------------------------------------------------------------------
class CMemoryBSPFile
{
public:
CMemoryBSPFile();
//-----------------------------------------------------------------------------
// Grabs data from the BSP class and serializes it to the output buffer.
// The output buffer must be at the start of an empty output stream.
//-----------------------------------------------------------------------------
void ProcessAndSerialize( CUtlBuffer *pOutputBuffer, const CSimpleBSPFile *pSimpleBSPFile );
//-----------------------------------------------------------------------------
// Writes data to a .bsp file buffer.
//-----------------------------------------------------------------------------
void Serialize( CUtlBuffer *pOutputBuffer );
//-----------------------------------------------------------------------------
// Reads .bsp data from a buffer into lump-specific arrays.
// Class can then be modified and re-saved to disk with Serialize().
//-----------------------------------------------------------------------------
void Deserialize( CUtlBuffer *pInputBuffer );
bool TryGetFaceVertex( int nFace, int nVertexIndex, Vector *pPosition ) const;
int GetLeafIndexFromPoint( int nNodeIndex, const Vector &vPosition ) const;
private:
bool IsHeaderValid() { return m_FileHeader.ident == IDBSPHEADER; }
// Begin & End are used when you want to manually Put() data into the buffer
void BeginWriteLump( int nLump, int nByteLength, int nVersion = 0 );
void EndWriteLump();
// Writes a whole lump (do not call Begin/EndWriteLump)
void WriteLump( int nLump, const void *pData, int nByteLength, int nVersion = 0 );
template< typename T >
void WriteLump( int nLump, const CUtlVector< T > &data, int nVersion = 0 );
// Begin & End are used when you want to manually Get() data from the buffer
int BeginReadLump( int nLump ); // returns size of the lump
void EndReadLump();
// Read a lump into an array (do not call Begin/EndReadLump)
template< typename T >
void ReadLump( int nLump, CUtlVector< T > *pVector );
void BuildTexInfo();
void WriteTexInfo( bool bPurgeWhenComplete );
void BuildTexData();
int FindOrAddString( const char *pString );
void WriteTexData( bool bPurgeWhenComplete );
void BuildModelData();
void WriteModelData( bool bPurgeWhenComplete );
void WritePortalFaces( const CBSPNode *pNode );
// There are 3 types of faces that can be emitted:
// 1) Portal faces, emitted all at once when a model is written
// 2) Detail faces, emitted after portal faces (also all at once when a model is written)
// 3) Displacement faces, emitted only for the world model (model #0), written all at once with the world model
void EmitFace( const CBSPFace *pBSPFace, bool bOnNode );
void BuildBSPTreeData();
void WriteBSPTreeData( bool bPurgeWhenComplete );
int32 EmitLeaf( const CBSPNode *pNode );
int32 EmitNode( const CBSPNode *pNode );
void BuildBrushes();
void WriteBrushes( bool bPurgeWhenComplete );
void BuildPlanes();
void WritePlanes( bool bPurgeWhenComplete );
void WriteModels( bool bPurgeWhenComplete );
void WriteDummyAreasAndAreaPortals();
void BuildGameLumpData();
void EmitStaticProp( const MapEntity_t *pEntity, CUtlVector< StaticPropLump_t > *pStaticPropLump, CUtlVector< StaticPropLeafLump_t > *pStaticPropLeafLump, CUtlVector< StaticPropDictLump_t > *pStaticPropDictionaryLump );
int AddStaticPropDictionaryEntry( const char *pModelName, CUtlVector< StaticPropDictLump_t > *pStaticPropDictionaryLump );
int AddStaticPropLeaves( const Vector &vOrigin, int nNodeIndex, CUtlVector< StaticPropLeafLump_t > *pStaticPropLeafLump );
void WriteGameLumpData( bool bPurgeWhenComplete );
void BuildEntityData();
void StripTrailingJunkCharacters( char *pString );
void WriteEntityData( bool bPurgeWhenComplete );
void BuildVisibilityData();
void WriteVisibilityData( bool bPurgeWhenComplete );
void BuildDisplacements();
void WriteDisplacements( bool bPurgeWhenComplete );
void BuildPhysicsCollisionData();
CPhysCollisionEntry * CreateWorldPhysicsModels(
IPhysicsCollision *pPhysicsCollision,
CUtlVector< int > *pWorldPropertyRemapList,
const int *pSurfacePropertyList,
const dmodel_t *pModel,
MapBrushContentsFlags_t contentsMask );
CPhysCollisionEntry * CreatePhysicsModel(
IPhysicsCollision *pPhysicsCollision,
IPhysicsSurfaceProps *pPhysicsProperties,
const int *pSurfacePropertyList,
const dmodel_t *pModel );
void BuildDisplacementVirtualMesh( IPhysicsCollision *pPhysicsCollision );
const MapBrushSide_t *FindClosestBrushSide( int nBrushIndex, const Vector &vNormal );
int RemapWorldMaterial( CUtlVector< int > *pWorldPropertyRemapList, int nSurfacePropertyIndex );
void WritePhysicsCollisionData( bool bPurgeWhenComplete );
void WriteLightingData( bool bPurgeWhenComplete );
CUtlBuffer *m_pSerialBuffer;
const CSimpleBSPFile *m_pSimpleBSPFile;
const CSimpleMapFile *m_pMapFile;
CPlaneHash m_PlaneHash;
BSPHeader_t m_FileHeader;
public:
// The following arrays map 1:1 with on-disk BSP data.
CUtlVector< texinfo_t > m_TexInfoList;
CUtlVector< dtexdata_t > m_TexDataList;
CUtlVector< char > m_TexStringData;
CUtlVector< int32 > m_TexStringIndices;
CUtlVector< dmodel_t > m_ModelList;
CVertexHash m_VertexHash;
CUtlVector< dedge_t > m_EdgeList;
CUtlVector< int32 > m_SurfEdgeList;
CUtlVector< dface_t > m_FaceList;
CUtlVector< Vector > m_VertexNormalList;
CUtlVector< uint16 > m_VertexNormalIndexList;
CUtlVector< dnode_t > m_NodeList;
CUtlVector< dleaf_t > m_LeafList;
CUtlVector< uint16 > m_LeafBrushList;
CUtlVector< uint16 > m_LeafFaceList;
CUtlVector< dbrush_t > m_BrushList;
CUtlVector< dbrushside_t > m_BrushSideList;
CUtlVector< dplane_t > m_Planes;
CUtlVector< byte > m_GameLumpData;
CUtlVector< byte > m_EntityData;
CUtlVector< byte > m_VisibilityData;
CUtlVector< CCoreDispInfo * > m_DisplacementHelperList;
CUtlVector< ddispinfo_t > m_DisplacementList;
CUtlVector< CDispVert > m_DisplacementVertexList;
CUtlVector< CDispTri > m_DisplacementTriangleList;
CUtlVector< CDispMultiBlend > m_DisplacementMultiBlendList;
CUtlVector< byte > m_PhysicsDisplacementData;
CUtlVector< byte > m_PhysicsCollideData;
CUtlVector< byte > m_LightingData;
CUtlVector< dworldlight_t > m_WorldLightsLDR;
CUtlVector< dworldlight_t > m_WorldLightsHDR;
// If entityExclusionFlags[N] is set to true, then do not write entity data for entity NF
CBitVec< MAX_MAP_ENTITIES > m_EntityExclusionFlags;
};
#endif // SERIALIZESIMPLEBSPFILE_H

View File

@@ -0,0 +1,401 @@
//============ 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

View File

@@ -0,0 +1,425 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Class & functions to parse and represent a VMF file.
//
//===============================================================================
#ifndef SIMPLEMAPFILE_H
#define SIMPLEMAPFILE_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "chunkfile.h"
#include "stringpool.h"
#include "vbspmathutil.h"
class CSimpleMapFile;
class GameData;
DECLARE_LOGGING_CHANNEL( LOG_VBSP2 );
//-----------------------------------------------------------------------------
// Flags that modify a brush volume or brush side surface
//-----------------------------------------------------------------------------
typedef int MapBrushContentsFlags_t;
//-----------------------------------------------------------------------------
// Flags that modify a brush side surface
//-----------------------------------------------------------------------------
typedef short MapBrushSideSurfaceFlags_t;
//-----------------------------------------------------------------------------
// A single entity from a VMF file.
//-----------------------------------------------------------------------------
struct MapEntity_t
{
// World-space location of the object.
Vector m_vOrigin;
// Index & count of brushes contained within this entity. These are stored in the map's brush array.
// Brushes in an entity have contiguous indices in the range: [m_nFirstBrushIndex, m_nFirstBrushIndex + m_nNumBrushes).
int m_nFirstBrushIndex;
int m_nNumBrushes;
// Index & count of key-value pairs (entity properties) contained within this entity. These are stored in the map's key-value pair array.
// Key-value pairs in an entity have contiguous indices in the range: [m_nFirstKVPairIndex, m_nFirstKVPairIndex + m_nNumKVPairs).
int m_nFirstKVPairIndex;
int m_nNumKVPairs;
};
//-----------------------------------------------------------------------------
// A property of an entity from a VMF file.
//-----------------------------------------------------------------------------
struct MapEntityKeyValuePair_t
{
// These point into the string pool owned by the map object, so no memory management is necessary.
const char *m_pKey;
const char *m_pValue;
// True if this key value pair came from the "connections" section of an entity,
// false if it came from an ordinary entity key.
bool m_bIsConnection;
};
//-----------------------------------------------------------------------------
// A CSG brush (convex solid) from a VMF file.
//-----------------------------------------------------------------------------
struct MapBrush_t
{
// Contents of the brush, based on the properties of its sides.
MapBrushContentsFlags_t m_ContentsFlags;
// Index & count of brush sides. These are stored in the map's brush sides array.
// Brush sides have contiguous indices in the range: [m_nFirstSideIndex, m_nFirstSideIndex + m_nNumSides).
int m_nFirstSideIndex;
int m_nNumSides;
// AABB of the brush
Vector m_vMinBounds, m_vMaxBounds;
};
static const int INVALID_DISPLACEMENT_INDEX = -1;
//-----------------------------------------------------------------------------
// A single side of a CSG brush from a VMF file.
//-----------------------------------------------------------------------------
struct MapBrushSide_t
{
// Contents of the brush side, based on the material properties.
MapBrushContentsFlags_t m_ContentsFlags;
// Surface flags of the brush side, based on the material properties.
MapBrushSideSurfaceFlags_t m_SurfaceFlags;
// The index of the plane coincident with this brush side. The index is in the map's plane hash.
int m_nPlaneIndex;
// The index of the texture info struct for this brush side, describing the material applied to this side.
// The index is into the map's texture info array.
int m_nTextureInfoIndex;
// The polygonal face of this brush side.
Polygon_t m_Polygon;
// The index of the displacement associated with this side, or INVALID_DISPLACEMENT_INDEX if
// this side is not a displacement surface.
int m_nDisplacementIndex;
};
//-----------------------------------------------------------------------------
// A displacement surface, specified on a particular CSG brush side.
//-----------------------------------------------------------------------------
class CMapDisplacement
{
public:
CMapDisplacement();
bool AreVerticesAllocated() const { return m_Vertices.Count() > 0 && m_nPower > 0; }
// NOTE: If new fields are added to this class, you must update MoveFrom()!
// Power-of-2 number of subdivisions.
// MIN_MAP_DISP_POWER <= m_nPower <= MAX_MAP_DISP_POWER
int m_nPower;
// Map brush side corresponding to this displacement surface. The brush side is "orphaned"
// in that no brushes will point to it (since the original brush is removed from the world).
int m_nOriginalBrushSide;
// SURF_* flags, defined in builddisp.h
int m_nFlags;
// Contents flags taken from the original brush.
// The value is stored here, since the original brush gets removed from the world.
MapBrushContentsFlags_t m_ContentsFlags;
Vector m_vStartPosition;
struct Vertex_t
{
float m_flAlpha;
float m_flDistance;
Vector m_vNormal;
Vector m_vOffset;
Vector4D m_vMultiBlend;
Vector m_vMultiBlendColors[MAX_MULTIBLEND_CHANNELS];
};
CUtlVector< Vertex_t > m_Vertices;
// DISPTRI_* flags, defined in bspfile.h (one per triangle).
CUtlVector< unsigned short > m_TriangleTags;
// Copies values and takes ownership of owned data from the other displacement object
// (this is a destructive, but efficient, operation used to migrate a displacement
// from one map object to another).
// NOTE: If you add new fields to CMapDisplacement, you must update this function!
void MoveFrom( CMapDisplacement *pOther );
private:
// Disallow value semantics
CMapDisplacement( const CMapDisplacement &other );
CMapDisplacement &operator=( const CMapDisplacement &other );
};
static const int MAX_TEXTURE_NAME_LENGTH = 128;
//-----------------------------------------------------------------------------
// Texture properties for a brush side, as loaded from a VMF file.
//-----------------------------------------------------------------------------
struct MapBrushTexture_t
{
Vector m_vUAxis, m_vVAxis;
float m_flShift[2];
float m_flTextureWorldUnitsPerTexel[2];
float m_flLightmapWorldUnitsPerLuxel;
char m_MaterialName[MAX_TEXTURE_NAME_LENGTH];
MapBrushSideSurfaceFlags_t m_SurfaceFlags;
};
//-----------------------------------------------------------------------------
// Sentinel texture info index for a side of a solid BSP node.
//-----------------------------------------------------------------------------
static const int NODE_TEXTURE_INFO_INDEX = -1;
//-----------------------------------------------------------------------------
// Planar mapping of texture data to a particular surface.
//-----------------------------------------------------------------------------
struct MapTextureInfo_t
{
// The U and V vectors (w-component contains the offset) that define
// a homogeneous planar mapping from 3D (world) space to 2D (texture) space.
float m_flTextureVectors[2][4];
float m_flLightmapVectors[2][4];
// Index into the map's texture data array of the structure which describes
// the material being mapped to this surface.
int m_nTextureDataIndex;
MapBrushSideSurfaceFlags_t m_SurfaceFlags;
};
//-----------------------------------------------------------------------------
// Basic material information for a surface.
//-----------------------------------------------------------------------------
struct MapTextureData_t
{
Vector m_vReflectivity;
// Width and height of the base texture referenced by the material
int m_nWidth, m_nHeight;
// Name of the material (e.g. DEV/GRAYGRID) being mapped
char m_MaterialName[MAX_TEXTURE_NAME_LENGTH];
};
//-----------------------------------------------------------------------------
// Finds a key-value pair with the specified key in a given array of
// key-value pairs, or NULL if none is found
//-----------------------------------------------------------------------------
const MapEntityKeyValuePair_t *FindPair( const char *pKeyName, const MapEntityKeyValuePair_t *pPairs, int nNumPairs );
MapEntityKeyValuePair_t *FindPair( const char *pKeyName, MapEntityKeyValuePair_t *pPairs, int nNumPairs );
//-----------------------------------------------------------------------------
// Gets the value associated with the given pair or "" if the pair
// or value string is NULL (safe to chain with FindPair)
//-----------------------------------------------------------------------------
const char *GetPairValue( const MapEntityKeyValuePair_t *pPair );
//-----------------------------------------------------------------------------
// A class which represents a VMF (map) file in memory
// or value string is NULL (safe to chain with FindPair)
//-----------------------------------------------------------------------------
class CSimpleMapFile
{
public:
//-----------------------------------------------------------------------------
// Gets the minimum and maximum bound of all world brushes in this map file
//-----------------------------------------------------------------------------
Vector GetMinBounds() const { return m_vMinBounds; }
Vector GetMaxBounds() const { return m_vMaxBounds; }
int GetMapRevision() const { return m_nMapRevision; }
const MapEntity_t *GetEntities() const { return &m_Entities[0]; }
MapEntity_t *GetEntities() { return &m_Entities[0]; }
int GetEntityCount() const { return m_Entities.Count(); }
//-----------------------------------------------------------------------------
// Gets the world entity, which is the 0th entity in the file
//-----------------------------------------------------------------------------
const MapEntity_t *GetWorldEntity() const { return GetEntities(); }
MapEntity_t *GetWorldEntity() { return GetEntities(); }
const MapBrush_t *GetBrushes() const { return &m_Brushes[0]; }
MapBrush_t *GetBrushes() { return &m_Brushes[0]; }
int GetBrushCount() const { return m_Brushes.Count(); }
const MapBrushSide_t *GetBrushSides() const { return &m_BrushSides[0]; }
MapBrushSide_t *GetBrushSides() { return &m_BrushSides[0]; }
int GetBrushSideCount() const { return m_BrushSides.Count(); }
const CMapDisplacement *GetDisplacements() const { return &m_Displacements[0]; }
CMapDisplacement *GetDisplacements() { return &m_Displacements[0]; }
int GetDisplacementCount() const { return m_Displacements.Count(); }
const MapTextureInfo_t *GetTextureInfos() const { return &m_TextureInfos[0]; }
MapTextureInfo_t *GetTextureInfos() { return &m_TextureInfos[0]; }
int GetTextureInfoCount() const { return m_TextureInfos.Count(); }
const MapTextureData_t *GetTextureData() const { return &m_TextureData[0]; }
MapTextureData_t *GetTextureData() { return &m_TextureData[0]; }
int GetTextureDataCount() const { return m_TextureData.Count(); }
const MapEntityKeyValuePair_t *GetKeyValuePairs() const { return &m_KeyValuePairs[0]; }
MapEntityKeyValuePair_t *GetKeyValuePairs() { return &m_KeyValuePairs[0]; }
int GetKeyValuePairCount() const { return m_KeyValuePairs.Count(); }
const CPlaneHash *GetPlaneHash() const { return &m_PlaneHash; }
const char *GetFilename() const { return m_pFilename; }
//-----------------------------------------------------------------------------
// Adds a func_instance entity to the map file.
//-----------------------------------------------------------------------------
void AddFuncInstance( const char *pFilename, QAngle angles, Vector vOrigin, MapEntityKeyValuePair_t *pExtraKeyValues = NULL, int nExtraKeyValues = 0 );
int FindEntity( const char *pClassName, const char *pKeyName, const char *pValue, int nStartingIndex = 0 );
void RemoveEntity( int nEntityIndex );
//-----------------------------------------------------------------------------
// Flags passed to ResolveInstances() to control behavior.
//-----------------------------------------------------------------------------
enum ResolveInstanceFlags_t
{
NO_FLAGS = 0x0,
CONVERT_STRUCTURAL_TO_DETAIL = 0x1, // convert all solids in world entities to func_detail
};
//-----------------------------------------------------------------------------
// Callback invoked after loading each instance.
// The callback is given the originally provided context value, the loaded
// instance map, and the key-value pairs from the parent map's
// func_instance entity chunk.
//-----------------------------------------------------------------------------
typedef void ( *PostLoadInstanceHandler_t )( void *pContext, CSimpleMapFile *pInstanceMapFile, MapEntityKeyValuePair_t *pFuncInstanceKeyValuePairs, int nNumKeyValuePairs );
//-----------------------------------------------------------------------------
// Recursively loads all contained func_instance entities and merges
// them with the current map in breadth-first recursive order.
//-----------------------------------------------------------------------------
bool ResolveInstances( ResolveInstanceFlags_t instanceFlags = NO_FLAGS, PostLoadInstanceHandler_t pPostLoadInstanceHandler = NULL, void *pHandlerContext = NULL );
//-----------------------------------------------------------------------------
// Loads a VMF (map) file from disk and constructs a new CSimpleMapFile object.
// The caller must delete the object when done.
//-----------------------------------------------------------------------------
static void LoadFromFile( IFileSystem *pFileSystem, const char *pVMFFilename, CSimpleMapFile **ppNewMapFile, ResolveInstanceFlags_t instanceFlags = NO_FLAGS );
private:
CSimpleMapFile( IFileSystem *pFileSystem, const char *pVMFFilename );
MapEntity_t *AllocateNewEntity();
MapBrush_t *AllocateNewBrush();
MapBrushSide_t *AllocateNewBrushSide();
CMapDisplacement *AllocateNewDisplacement();
MapBrushTexture_t *AllocateNewBrushTexture();
MapTextureData_t *AllocateNewTextureData();
MapEntityKeyValuePair_t *AllocateNewKeyValuePair();
// Some entity types are simply ignored
void DeallocateLastEntity() { m_Entities.RemoveMultipleFromTail( 1 ); }
// Some brushes are loaded and then discarded (e.g. brushes with displacement)
void DeallocateLastBrush() { m_Brushes.RemoveMultipleFromTail( 1 ); }
void ReportParseError( const char *pErrorString );
void MakeBrushPolygons( MapBrush_t *pBrush );
void MoveEntityBrushesToWorld( int nEntityIndex );
int GetTextureInfoForBrushTexture( MapBrushTexture_t *pBrushTexture, const Vector &vRelativeOrigin );
int FindOrCreateTextureData( const char *pTextureName );
int FindOrCreateTextureInfo( const MapTextureInfo_t &textureInfo );
MapBrushContentsFlags_t ComputeBrushContents( MapBrush_t *b );
// Functions used to merge instance data (recursively) with the primary map
void MergeInstance( int nEntityIndex, CSimpleMapFile *pInstanceMap, GameData *pGameData );
void PreLoadInstances( GameData *pGD );
void MergeBrushes( int nEntityIndex, const CSimpleMapFile *pInstanceMap, const Vector &vOrigin, const QAngle &orientation, const matrix3x4_t &transform );
void MergeBrushSides( int nEntityIndex, CSimpleMapFile *pInstanceMap, const Vector &vOrigin, const QAngle &orientation, const matrix3x4_t &transform );
void MergeEntities( int nEntityIndex, const CSimpleMapFile *pInstanceMap, const Vector &vOrigin, const QAngle &orientation, const matrix3x4_t &transform, GameData *pGameData );
void FixupInstanceKeyValuePair( MapEntityKeyValuePair_t *pNewKeyValuePair, const char *pOriginalValue, const MapEntityKeyValuePair_t *pInstancePairs, int nNumPairs );
// The following static functions are passed as callbacks to the chunk file reader
// when certain chunks and key blocks are encountered in the VMF file.
static ChunkFileResult_t EntityChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t SolidChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t SideChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DispInfoChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t ConnectionsChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t EntityKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t SolidKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t SideKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementKeyHandler( const char *pKey, const char *pValue, void *pData );
// These are shim functions which simply call into their corresponding displacement key handlers
static ChunkFileResult_t DisplacementNormalsChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementDistancesChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementOffsetsChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementAlphasChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementTriangleTagsChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementMultiBlendChunkHandler( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementMultiBlendColor0( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementMultiBlendColor1( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementMultiBlendColor2( CChunkFile *pFile, void *pData );
static ChunkFileResult_t DisplacementMultiBlendColor3( CChunkFile *pFile, void *pData );
// These read the actual key data associated with each displacement attribute
static ChunkFileResult_t DisplacementNormalsKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementDistancesKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementOffsetsKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementAlphasKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementTriangleTagsKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementMultiBlendKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t DisplacementMultiBlendColorKeyHandler( const char *pKey, const char *pValue, void *pData );
static ChunkFileResult_t ConnectionsKeyHandler( const char *pKey, const char *pValue, void *pData );
struct MaterialInfo_t
{
char m_Name[MAX_TEXTURE_NAME_LENGTH];
MapBrushContentsFlags_t m_ContentsFlags;
MapBrushSideSurfaceFlags_t m_SurfaceFlags;
};
MaterialInfo_t* FindMaterialInfo( const char *pName );
IFileSystem *m_pFileSystem;
// This is needed so instances can be resolved. If we're loading map files from memory buffers
// or other non-file sources, we'll need an "include interface" (like D3DX/HLSL's include resolution system).
const char *m_pFilename;
CPlaneHash m_PlaneHash;
CUtlVector< MapEntity_t > m_Entities;
CUtlVector< MapBrush_t > m_Brushes;
CUtlVector< CMapDisplacement > m_Displacements;
// These two arrays (m_BrushSides & m_BrushTextures) should always be the same size as there is a 1:1 correspondence.
CUtlVector< MapBrushSide_t > m_BrushSides;
CUtlVector< MapBrushTexture_t > m_BrushTextures;
CUtlVector< MapTextureInfo_t > m_TextureInfos;
CUtlVector< MapTextureData_t > m_TextureData;
// Number of instances loaded (recursively).
// This value is only used on the root-level map. It is used to generate unique names for instanced entities.
int m_nInstanceCount;
// This value is only used on instance maps to control loading and processing.
ResolveInstanceFlags_t m_InstanceFlags;
// Used to store entity property data
CUtlVector< MapEntityKeyValuePair_t > m_KeyValuePairs;
CStringPool m_KeyValueStringPool;
Vector m_vMinBounds, m_vMaxBounds;
int m_nMapRevision;
int m_nHighestID;
// Used to cache results of FindMaterialInfo, which gets information about materials applied to brush sides.
CUtlVector< MaterialInfo_t > m_MaterialInfos;
};
#endif // SIMPLEMAPFILE_H

View File

@@ -0,0 +1,238 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// Utility functions for BSP and map file math operations.
//
//===============================================================================
#ifndef VBSPMATHUTIL_H
#define VBSPMATHUTIL_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "utlvector.h"
#include "mathlib/vector.h"
#include "worldsize.h"
#include "bspfile.h"
DECLARE_LOGGING_CHANNEL( LOG_VBSP2 );
//-----------------------------------------------------------------------------
// A threshold used to determine whether coordinates of two normals are equal.
//-----------------------------------------------------------------------------
static const float c_flNormalEpsilon = 0.00001f;
//-----------------------------------------------------------------------------
// A threshold used to determine whether the distance value of two planes
// are equal. Also used for rounding coordinates to the nearest integer.
//-----------------------------------------------------------------------------
static const float c_flDistanceEpsilon = 0.01f;
//-----------------------------------------------------------------------------
// Threshold used to determine whether something is entirely on one side
// of a plane or another.
//-----------------------------------------------------------------------------
static const float c_flPlaneSideEpsilon = 0.1f;
//-----------------------------------------------------------------------------
// Threshold used to determine whether points should be snapped to each other.
//-----------------------------------------------------------------------------
static const float c_flWeldVertexEpsilon = 0.1f;
//-----------------------------------------------------------------------------
// Threshold used when clipping to determine whether a point is on a plane
// or on a particular side.
//-----------------------------------------------------------------------------
static const float c_flPlaneClipEpsilon = 0.01f;
//-----------------------------------------------------------------------------
// Polygons with more points than this are not handled properly by
// the system.
//-----------------------------------------------------------------------------
static const int MAX_POINTS_ON_POLYGON = 64;
//-----------------------------------------------------------------------------
// Represents a plane.
// Unlike a standard plane equation, a point P is defined to be on a plane if
// P * m_vNormal - m_flDistance == 0.
// A point P is defined to be in the positive half-space if
// P * m_vNormal - m_flDistance > 0.
// (In a standard plane equation that minus sign is a plus sign)
//-----------------------------------------------------------------------------
struct Plane_t
{
Vector m_vNormal;
float m_flDistance;
// A value in the range [0,5] which indicates the axis alignment,
// e.g. PLANE_X, PLANE_Y, PLANE_Z, PLANE_ANYX, PLANE_ANYY, PLANE_ANYZ
int m_Type;
};
//-----------------------------------------------------------------------------
// Flags indicating on which side of a plane something lies.
//-----------------------------------------------------------------------------
enum PlaneSide_t
{
PLANE_SIDE_INVALID = 0,
PLANE_SIDE_FRONT = 1,
PLANE_SIDE_BACK = 2,
PLANE_SIDE_BOTH = PLANE_SIDE_FRONT | PLANE_SIDE_BACK,
// "Facing" means that the point or face is directly on the plane;
// this may be combined with front or back to take into account
// direction.
PLANE_SIDE_FACING = 4,
};
//-----------------------------------------------------------------------------
// Returns which side of a plane a bounding box is on.
//-----------------------------------------------------------------------------
PlaneSide_t GetPlaneSide( const Vector &vMin, const Vector &vMax, Plane_t *pPlane );
//-----------------------------------------------------------------------------
// Snaps the plane to be axis-aligned if it is within an epsilon of axial.
//-----------------------------------------------------------------------------
bool SnapVector( Vector &vNormal );
//-----------------------------------------------------------------------------
// Snaps the plane to be axis-aligned if it is within an epsilon of axial.
// Recalculates dist if the vNormal was snapped. Rounds dist to integer
// if it is within an epsilon of integer.
//
// vNormal - Plane vNormal vector (assumed to be unit length).
// flDistance - Plane constant.
// v0, v1, v2 - Three points on the plane.
//-----------------------------------------------------------------------------
void SnapPlane( Vector &vNormal, vec_t &flDistance, const Vector &v0, const Vector &v1, const Vector &v2 );
//-----------------------------------------------------------------------------
// Returns true if one plane representation is equal to the other,
// within an epsilon threshold.
//-----------------------------------------------------------------------------
bool PlaneEqual( Plane_t *pPlane, const Vector &vNormal, float flDistance );
//-----------------------------------------------------------------------------
// Returns a value classifying the plane based on its axis alignment,
// e.g. PLANE_X, PLANE_Y, PLANE_Z, PLANE_ANYX, PLANE_ANYY, PLANE_ANYZ
//-----------------------------------------------------------------------------
int GetPlaneTypeFromNormal( const Vector &vNormal );
//-----------------------------------------------------------------------------
// Compute a normal for a triangle, given three points.
// The points are clockwise when looking at the triangle from the normal side.
//-----------------------------------------------------------------------------
Vector TriangleNormal( const Vector &v0, const Vector &v1, const Vector &v2 );
//-----------------------------------------------------------------------------
// A polygon used to represent faces on maps, BSPs, etc.
// This class is copyable.
//-----------------------------------------------------------------------------
class Polygon_t
{
public:
CCopyableUtlVector< Vector > m_Points;
};
//-----------------------------------------------------------------------------
// Computes whether a given polygon is tiny, relative to an epsilon threshold
//-----------------------------------------------------------------------------
bool IsPolygonTiny( Polygon_t *pPolygon );
//-----------------------------------------------------------------------------
// Checks all points in a polygon against the min and max coordinates.
//-----------------------------------------------------------------------------
bool IsPolygonHuge( Polygon_t *pPolygon );
//-----------------------------------------------------------------------------
// Computes the area of a polygon
//-----------------------------------------------------------------------------
float ComputePolygonArea( const Polygon_t &polygon );
//-----------------------------------------------------------------------------
// Creates a large polygon with extremal coordinates that lies on the plane
//-----------------------------------------------------------------------------
void CreatePolygonFromPlane( const Vector &vNormal, float flDistance, Polygon_t *pPolygon );
//-----------------------------------------------------------------------------
// Clips a polygon against a plane, creating* either:
// 1) One new, identical polygon (pOn), if the polygon is coincident
// with the plane.
// 2) One new, identical polygon (either pFront or pBack) if the polygon
// is entirely on one side of the plane.
// 3) Two new, different polygons (pFront and pBack) if the polygon is
// clipped by the plane
//
// If pOn is NULL, the "on" case is ignored and treated as either front
// or back appropriately.
//
// *The passed-in polygons (pOn, pFront, pBack) have their point arrays
// cleared at the start of the function. They are considered to be
// "created" upon exit if their point array has a non-zero point count.
//-----------------------------------------------------------------------------
void ChopPolygon( const Polygon_t &polygon, const Vector &vNormal, float flDistance, Polygon_t *pOn, Polygon_t *pFront, Polygon_t *pBack );
//-----------------------------------------------------------------------------
// Clips a polygon against a plane. If the polygon is completely clipped,
// pPolygon->m_Points will be empty ( Count() == 0 ).
//-----------------------------------------------------------------------------
void ChopPolygonInPlace( Polygon_t *pPolygon, const Vector &vNormal, float flDistance );
//-----------------------------------------------------------------------------
// A plane which can be stored efficiently in a hash table for fast lookup.
//-----------------------------------------------------------------------------
struct HashedPlane_t : public Plane_t
{
int m_nNextPlaneIndex;
};
// Make sure this is a power of 2, code depends on it.
static const int PLANE_HASH_TABLE_SIZE = 1024;
//-----------------------------------------------------------------------------
// A class to hash and pool planes.
//-----------------------------------------------------------------------------
class CPlaneHash
{
public:
CPlaneHash();
int FindPlaneIndex( const Vector &vNormal, float flDistance );
int FindPlaneIndex( Vector vPoints[3] );
CCopyableUtlVector< HashedPlane_t > m_Planes;
private:
HashedPlane_t *AllocateNewPlane();
// Hash table consisting of indices into the m_Planes array
int m_HashTable[PLANE_HASH_TABLE_SIZE];
};
//-----------------------------------------------------------------------------
// A class to hash, weld, and pool vertices.
//-----------------------------------------------------------------------------
class CVertexHash
{
public:
CVertexHash();
CUtlVector< Vector > &GetVertices() { return m_Vertices; }
const CUtlVector< Vector > &GetVertices() const { return m_Vertices; }
void Purge();
// If bAlwaysAdd is true, this will skip the hash check and always add a new vertex
// (useful if vertex indices must be kept consistent and duplicates might exist)
int FindVertexIndex( const Vector &vertex, bool bAlwaysAdd = false );
private:
static const int m_nHashBitShift = 8;
static const int m_nHashLength = COORD_EXTENT >> m_nHashBitShift;
// Hash along the X and Y axes by grouping vertices into hash buckets
// which are NxN square columns of space.
// ~64 KB
int m_nVertexHash[m_nHashLength * m_nHashLength];
CUtlVector< int > m_VertexHashChain;
CUtlVector< Vector > m_Vertices;
};
#endif // VBSPMATHUTIL_H