doom3-bfg/neo/cm/CollisionModel_local.h
Daniel Gibson ee88148bd1 eliminate more longs
for 64bit compatibility.
2012-12-13 01:28:41 +01:00

564 lines
26 KiB
C++

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "CollisionModel.h"
#define MIN_NODE_SIZE 64.0f
#define MAX_NODE_POLYGONS 128
#define CM_MAX_POLYGON_EDGES 64
#define CIRCLE_APPROXIMATION_LENGTH 64.0f
#define MAX_SUBMODELS 2048
#define TRACE_MODEL_HANDLE MAX_SUBMODELS
#define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
#define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
#define EDGE_HASH_SIZE (1<<14)
#define NODE_BLOCK_SIZE_SMALL 8
#define NODE_BLOCK_SIZE_LARGE 256
#define REFERENCE_BLOCK_SIZE_SMALL 8
#define REFERENCE_BLOCK_SIZE_LARGE 256
#define MAX_WINDING_LIST 128 // quite a few are generated at times
#define INTEGRAL_EPSILON 0.01f
#define VERTEX_EPSILON 0.1f
#define CHOP_EPSILON 0.1f
typedef struct cm_windingList_s
{
int numWindings; // number of windings
idFixedWinding w[MAX_WINDING_LIST]; // windings
idVec3 normal; // normal for all windings
idBounds bounds; // bounds of all windings in list
idVec3 origin; // origin for radius
float radius; // radius relative to origin for all windings
int contents; // winding surface contents
int primitiveNum; // number of primitive the windings came from
} cm_windingList_t;
/*
===============================================================================
Collision model
===============================================================================
*/
typedef struct cm_vertex_s
{
idVec3 p; // vertex point
int checkcount; // for multi-check avoidance
// DG: use int instead of long for 64bit compatibility
unsigned int side; // each bit tells at which side this vertex passes one of the trace model edges
unsigned int sideSet; // each bit tells if sidedness for the trace model edge has been calculated yet
// DG end
} cm_vertex_t;
typedef struct cm_edge_s
{
int checkcount; // for multi-check avoidance
unsigned short internal; // a trace model can never collide with internal edges
unsigned short numUsers; // number of polygons using this edge
// DG: use int instead of long for 64bit compatibility
unsigned int side; // each bit tells at which side of this edge one of the trace model vertices passes
unsigned int sideSet; // each bit tells if sidedness for the trace model vertex has been calculated yet
// DG end
int vertexNum[2]; // start and end point of edge
idVec3 normal; // edge normal
} cm_edge_t;
typedef struct cm_polygonBlock_s
{
int bytesRemaining;
byte* next;
} cm_polygonBlock_t;
typedef struct cm_polygon_s
{
idBounds bounds; // polygon bounds
int checkcount; // for multi-check avoidance
int contents; // contents behind polygon
const idMaterial* material; // material
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[1]; // variable sized, indexes into cm_edge_t list
} cm_polygon_t;
typedef struct cm_polygonRef_s
{
cm_polygon_t* p; // pointer to polygon
struct cm_polygonRef_s* next; // next polygon in chain
} cm_polygonRef_t;
typedef struct cm_polygonRefBlock_s
{
cm_polygonRef_t* nextRef; // next polygon reference in block
struct cm_polygonRefBlock_s* next; // next block with polygon references
} cm_polygonRefBlock_t;
typedef struct cm_brushBlock_s
{
int bytesRemaining;
byte* next;
} cm_brushBlock_t;
typedef struct cm_brush_s
{
cm_brush_s()
{
checkcount = 0;
contents = 0;
material = NULL;
primitiveNum = 0;
numPlanes = 0;
}
int checkcount; // for multi-check avoidance
idBounds bounds; // brush bounds
int contents; // contents of brush
const idMaterial* material; // material
int primitiveNum; // number of brush primitive
int numPlanes; // number of bounding planes
idPlane planes[1]; // variable sized
} cm_brush_t;
typedef struct cm_brushRef_s
{
cm_brush_t* b; // pointer to brush
struct cm_brushRef_s* next; // next brush in chain
} cm_brushRef_t;
typedef struct cm_brushRefBlock_s
{
cm_brushRef_t* nextRef; // next brush reference in block
struct cm_brushRefBlock_s* next; // next block with brush references
} cm_brushRefBlock_t;
typedef struct cm_node_s
{
int planeType; // node axial plane type
float planeDist; // node plane distance
cm_polygonRef_t* polygons; // polygons in node
cm_brushRef_t* brushes; // brushes in node
struct cm_node_s* parent; // parent of this node
struct cm_node_s* children[2]; // node children
} cm_node_t;
typedef struct cm_nodeBlock_s
{
cm_node_t* nextNode; // next node in block
struct cm_nodeBlock_s* next; // next block with nodes
} cm_nodeBlock_t;
typedef struct cm_model_s
{
idStr name; // model name
idBounds bounds; // model bounds
int contents; // all contents of the model ored together
bool isConvex; // set if model is convex
// model geometry
int maxVertices; // size of vertex array
int numVertices; // number of vertices
cm_vertex_t* vertices; // array with all vertices used by the model
int maxEdges; // size of edge array
int numEdges; // number of edges
cm_edge_t* edges; // array with all edges used by the model
cm_node_t* node; // first node of spatial subdivision
// blocks with allocated memory
cm_nodeBlock_t* nodeBlocks; // list with blocks of nodes
cm_polygonRefBlock_t* polygonRefBlocks; // list with blocks of polygon references
cm_brushRefBlock_t* brushRefBlocks; // list with blocks of brush references
cm_polygonBlock_t* polygonBlock; // memory block with all polygons
cm_brushBlock_t* brushBlock; // memory block with all brushes
// statistics
int numPolygons;
int polygonMemory;
int numBrushes;
int brushMemory;
int numNodes;
int numBrushRefs;
int numPolygonRefs;
int numInternalEdges;
int numSharpEdges;
int numRemovedPolys;
int numMergedPolys;
int usedMemory;
} cm_model_t;
/*
===============================================================================
Data used during collision detection calculations
===============================================================================
*/
typedef struct cm_trmVertex_s
{
int used; // true if this vertex is used for collision detection
idVec3 p; // vertex position
idVec3 endp; // end point of vertex after movement
int polygonSide; // side of polygon this vertex is on (rotational collision)
idPluecker pl; // pluecker coordinate for vertex movement
idVec3 rotationOrigin; // rotation origin for this vertex
idBounds rotationBounds; // rotation bounds for this vertex
} cm_trmVertex_t;
typedef struct cm_trmEdge_s
{
int used; // true when vertex is used for collision detection
idVec3 start; // start of edge
idVec3 end; // end of edge
int vertexNum[2]; // indexes into cm_traceWork_t->vertices
idPluecker pl; // pluecker coordinate for edge
idVec3 cross; // (z,-y,x) of cross product between edge dir and movement dir
idBounds rotationBounds; // rotation bounds for this edge
idPluecker plzaxis; // pluecker coordinate for rotation about the z-axis
unsigned short bitNum; // vertex bit number
} cm_trmEdge_t;
typedef struct cm_trmPolygon_s
{
int used;
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[MAX_TRACEMODEL_POLYEDGES]; // index into cm_traceWork_t->edges
idBounds rotationBounds; // rotation bounds for this polygon
} cm_trmPolygon_t;
typedef struct cm_traceWork_s
{
int numVerts;
cm_trmVertex_t vertices[MAX_TRACEMODEL_VERTS]; // trm vertices
int numEdges;
cm_trmEdge_t edges[MAX_TRACEMODEL_EDGES + 1]; // trm edges
int numPolys;
cm_trmPolygon_t polys[MAX_TRACEMODEL_POLYS]; // trm polygons
cm_model_t* model; // model colliding with
idVec3 start; // start of trace
idVec3 end; // end of trace
idVec3 dir; // trace direction
idBounds bounds; // bounds of full trace
idBounds size; // bounds of transformed trm relative to start
idVec3 extents; // largest of abs(size[0]) and abs(size[1]) for BSP trace
int contents; // ignore polygons that do not have any of these contents flags
trace_t trace; // collision detection result
bool rotation; // true if calculating rotational collision
bool pointTrace; // true if only tracing a point
bool positionTest; // true if not tracing but doing a position test
bool isConvex; // true if the trace model is convex
bool axisIntersectsTrm; // true if the rotation axis intersects the trace model
bool getContacts; // true if retrieving contacts
bool quickExit; // set to quickly stop the collision detection calculations
idVec3 origin; // origin of rotation in model space
idVec3 axis; // rotation axis in model space
idMat3 matrix; // rotates axis of rotation to the z-axis
float angle; // angle for rotational collision
float maxTan; // max tangent of half the positive angle used instead of fraction
float radius; // rotation radius of trm start
idRotation modelVertexRotation; // inverse rotation for model vertices
contactInfo_t* contacts; // array with contacts
int maxContacts; // max size of contact array
int numContacts; // number of contacts found
idPlane heartPlane1; // polygons should be near anough the trace heart planes
float maxDistFromHeartPlane1;
idPlane heartPlane2;
float maxDistFromHeartPlane2;
idPluecker polygonEdgePlueckerCache[CM_MAX_POLYGON_EDGES];
idPluecker polygonVertexPlueckerCache[CM_MAX_POLYGON_EDGES];
idVec3 polygonRotationOriginCache[CM_MAX_POLYGON_EDGES];
} cm_traceWork_t;
/*
===============================================================================
Collision Map
===============================================================================
*/
typedef struct cm_procNode_s
{
idPlane plane;
int children[2]; // negative numbers are (-1 - areaNumber), 0 = solid
} cm_procNode_t;
class idCollisionModelManagerLocal : public idCollisionModelManager
{
public:
// load collision models from a map file
void LoadMap( const idMapFile* mapFile );
// frees all the collision models
void FreeMap();
void Preload( const char* mapName );
// get clip handle for model
cmHandle_t LoadModel( const char* modelName );
// sets up a trace model for collision with other trace models
cmHandle_t SetupTrmModel( const idTraceModel& trm, const idMaterial* material );
// create trace model from a collision model, returns true if succesfull
bool TrmFromModel( const char* modelName, idTraceModel& trm );
// name of the model
const char* GetModelName( cmHandle_t model ) const;
// bounds of the model
bool GetModelBounds( cmHandle_t model, idBounds& bounds ) const;
// all contents flags of brushes and polygons ored together
bool GetModelContents( cmHandle_t model, int& contents ) const;
// get the vertex of a model
bool GetModelVertex( cmHandle_t model, int vertexNum, idVec3& vertex ) const;
// get the edge of a model
bool GetModelEdge( cmHandle_t model, int edgeNum, idVec3& start, idVec3& end ) const;
// get the polygon of a model
bool GetModelPolygon( cmHandle_t model, int polygonNum, idFixedWinding& winding ) const;
// translates a trm and reports the first collision if any
void Translation( trace_t* results, const idVec3& start, const idVec3& end,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& modelOrigin, const idMat3& modelAxis );
// rotates a trm and reports the first collision if any
void Rotation( trace_t* results, const idVec3& start, const idRotation& rotation,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& modelOrigin, const idMat3& modelAxis );
// returns the contents the trm is stuck in or 0 if the trm is in free space
int Contents( const idVec3& start,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& modelOrigin, const idMat3& modelAxis );
// stores all contact points of the trm with the model, returns the number of contacts
int Contacts( contactInfo_t* contacts, const int maxContacts, const idVec3& start, const idVec6& dir, const float depth,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& modelOrigin, const idMat3& modelAxis );
// test collision detection
void DebugOutput( const idVec3& origin );
// draw a model
void DrawModel( cmHandle_t model, const idVec3& origin, const idMat3& axis,
const idVec3& viewOrigin, const float radius );
// print model information, use -1 handle for accumulated model info
void ModelInfo( cmHandle_t model );
// list all loaded models
void ListModels();
// write a collision model file for the map entity
bool WriteCollisionModelForMapEntity( const idMapEntity* mapEnt, const char* filename, const bool testTraceModel = true );
private: // CollisionMap_translate.cpp
int TranslateEdgeThroughEdge( idVec3& cross, idPluecker& l1, idPluecker& l2, float* fraction );
void TranslateTrmEdgeThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* poly, cm_trmEdge_t* trmEdge );
void TranslateTrmVertexThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* poly, cm_trmVertex_t* v, int bitNum );
void TranslatePointThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* poly, cm_trmVertex_t* v );
void TranslateVertexThroughTrmPolygon( cm_traceWork_t* tw, cm_trmPolygon_t* trmpoly, cm_polygon_t* poly, cm_vertex_t* v, idVec3& endp, idPluecker& pl );
bool TranslateTrmThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* p );
void SetupTranslationHeartPlanes( cm_traceWork_t* tw );
void SetupTrm( cm_traceWork_t* tw, const idTraceModel* trm );
private: // CollisionMap_rotate.cpp
int CollisionBetweenEdgeBounds( cm_traceWork_t* tw, const idVec3& va, const idVec3& vb,
const idVec3& vc, const idVec3& vd, float tanHalfAngle,
idVec3& collisionPoint, idVec3& collisionNormal );
int RotateEdgeThroughEdge( cm_traceWork_t* tw, const idPluecker& pl1,
const idVec3& vc, const idVec3& vd,
const float minTan, float& tanHalfAngle );
int EdgeFurthestFromEdge( cm_traceWork_t* tw, const idPluecker& pl1,
const idVec3& vc, const idVec3& vd,
float& tanHalfAngle, float& dir );
void RotateTrmEdgeThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* poly, cm_trmEdge_t* trmEdge );
int RotatePointThroughPlane( const cm_traceWork_t* tw, const idVec3& point, const idPlane& plane,
const float angle, const float minTan, float& tanHalfAngle );
int PointFurthestFromPlane( const cm_traceWork_t* tw, const idVec3& point, const idPlane& plane,
const float angle, float& tanHalfAngle, float& dir );
int RotatePointThroughEpsilonPlane( const cm_traceWork_t* tw, const idVec3& point, const idVec3& endPoint,
const idPlane& plane, const float angle, const idVec3& origin,
float& tanHalfAngle, idVec3& collisionPoint, idVec3& endDir );
void RotateTrmVertexThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* poly, cm_trmVertex_t* v, int vertexNum );
void RotateVertexThroughTrmPolygon( cm_traceWork_t* tw, cm_trmPolygon_t* trmpoly, cm_polygon_t* poly,
cm_vertex_t* v, idVec3& rotationOrigin );
bool RotateTrmThroughPolygon( cm_traceWork_t* tw, cm_polygon_t* p );
void BoundsForRotation( const idVec3& origin, const idVec3& axis, const idVec3& start, const idVec3& end, idBounds& bounds );
void Rotation180( trace_t* results, const idVec3& rorg, const idVec3& axis,
const float startAngle, const float endAngle, const idVec3& start,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& origin, const idMat3& modelAxis );
private: // CollisionMap_contents.cpp
bool TestTrmVertsInBrush( cm_traceWork_t* tw, cm_brush_t* b );
bool TestTrmInPolygon( cm_traceWork_t* tw, cm_polygon_t* p );
cm_node_t* PointNode( const idVec3& p, cm_model_t* model );
int PointContents( const idVec3 p, cmHandle_t model );
int TransformedPointContents( const idVec3& p, cmHandle_t model, const idVec3& origin, const idMat3& modelAxis );
int ContentsTrm( trace_t* results, const idVec3& start,
const idTraceModel* trm, const idMat3& trmAxis, int contentMask,
cmHandle_t model, const idVec3& modelOrigin, const idMat3& modelAxis );
private: // CollisionMap_trace.cpp
void TraceTrmThroughNode( cm_traceWork_t* tw, cm_node_t* node );
void TraceThroughAxialBSPTree_r( cm_traceWork_t* tw, cm_node_t* node, float p1f, float p2f, idVec3& p1, idVec3& p2 );
void TraceThroughModel( cm_traceWork_t* tw );
void RecurseProcBSP_r( trace_t* results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3& p1, const idVec3& p2 );
private: // CollisionMap_load.cpp
void Clear();
void FreeTrmModelStructure();
// model deallocation
void RemovePolygonReferences_r( cm_node_t* node, cm_polygon_t* p );
void RemoveBrushReferences_r( cm_node_t* node, cm_brush_t* b );
void FreeNode( cm_node_t* node );
void FreePolygonReference( cm_polygonRef_t* pref );
void FreeBrushReference( cm_brushRef_t* bref );
void FreePolygon( cm_model_t* model, cm_polygon_t* poly );
void FreeBrush( cm_model_t* model, cm_brush_t* brush );
void FreeTree_r( cm_model_t* model, cm_node_t* headNode, cm_node_t* node );
void FreeModel( cm_model_t* model );
// merging polygons
void ReplacePolygons( cm_model_t* model, cm_node_t* node, cm_polygon_t* p1, cm_polygon_t* p2, cm_polygon_t* newp );
cm_polygon_t* TryMergePolygons( cm_model_t* model, cm_polygon_t* p1, cm_polygon_t* p2 );
bool MergePolygonWithTreePolygons( cm_model_t* model, cm_node_t* node, cm_polygon_t* polygon );
void MergeTreePolygons( cm_model_t* model, cm_node_t* node );
// finding internal edges
bool PointInsidePolygon( cm_model_t* model, cm_polygon_t* p, idVec3& v );
void FindInternalEdgesOnPolygon( cm_model_t* model, cm_polygon_t* p1, cm_polygon_t* p2 );
void FindInternalPolygonEdges( cm_model_t* model, cm_node_t* node, cm_polygon_t* polygon );
void FindInternalEdges( cm_model_t* model, cm_node_t* node );
void FindContainedEdges( cm_model_t* model, cm_polygon_t* p );
// loading of proc BSP tree
void ParseProcNodes( idLexer* src );
void LoadProcBSP( const char* name );
// removal of contained polygons
int R_ChoppedAwayByProcBSP( int nodeNum, idFixedWinding* w, const idVec3& normal, const idVec3& origin, const float radius );
int ChoppedAwayByProcBSP( const idFixedWinding& w, const idPlane& plane, int contents );
void ChopWindingListWithBrush( cm_windingList_t* list, cm_brush_t* b );
void R_ChopWindingListWithTreeBrushes( cm_windingList_t* list, cm_node_t* node );
idFixedWinding* WindingOutsideBrushes( idFixedWinding* w, const idPlane& plane, int contents, int patch, cm_node_t* headNode );
// creation of axial BSP tree
cm_model_t* AllocModel();
cm_node_t* AllocNode( cm_model_t* model, int blockSize );
cm_polygonRef_t* AllocPolygonReference( cm_model_t* model, int blockSize );
cm_brushRef_t* AllocBrushReference( cm_model_t* model, int blockSize );
cm_polygon_t* AllocPolygon( cm_model_t* model, int numEdges );
cm_brush_t* AllocBrush( cm_model_t* model, int numPlanes );
void AddPolygonToNode( cm_model_t* model, cm_node_t* node, cm_polygon_t* p );
void AddBrushToNode( cm_model_t* model, cm_node_t* node, cm_brush_t* b );
void SetupTrmModelStructure();
void R_FilterPolygonIntoTree( cm_model_t* model, cm_node_t* node, cm_polygonRef_t* pref, cm_polygon_t* p );
void R_FilterBrushIntoTree( cm_model_t* model, cm_node_t* node, cm_brushRef_t* pref, cm_brush_t* b );
cm_node_t* R_CreateAxialBSPTree( cm_model_t* model, cm_node_t* node, const idBounds& bounds );
cm_node_t* CreateAxialBSPTree( cm_model_t* model, cm_node_t* node );
// creation of raw polygons
void SetupHash();
void ShutdownHash();
void ClearHash( idBounds& bounds );
int HashVec( const idVec3& vec );
int GetVertex( cm_model_t* model, const idVec3& v, int* vertexNum );
int GetEdge( cm_model_t* model, const idVec3& v1, const idVec3& v2, int* edgeNum, int v1num );
void CreatePolygon( cm_model_t* model, idFixedWinding* w, const idPlane& plane, const idMaterial* material, int primitiveNum );
void PolygonFromWinding( cm_model_t* model, idFixedWinding* w, const idPlane& plane, const idMaterial* material, int primitiveNum );
void CalculateEdgeNormals( cm_model_t* model, cm_node_t* node );
void CreatePatchPolygons( cm_model_t* model, idSurface_Patch& mesh, const idMaterial* material, int primitiveNum );
void ConvertPatch( cm_model_t* model, const idMapPatch* patch, int primitiveNum );
void ConvertBrushSides( cm_model_t* model, const idMapBrush* mapBrush, int primitiveNum );
void ConvertBrush( cm_model_t* model, const idMapBrush* mapBrush, int primitiveNum );
void PrintModelInfo( const cm_model_t* model );
void AccumulateModelInfo( cm_model_t* model );
void RemapEdges( cm_node_t* node, int* edgeRemap );
void OptimizeArrays( cm_model_t* model );
void FinishModel( cm_model_t* model );
void BuildModels( const idMapFile* mapFile );
cmHandle_t FindModel( const char* name );
cm_model_t* CollisionModelForMapEntity( const idMapEntity* mapEnt ); // brush/patch model from .map
cm_model_t* LoadRenderModel( const char* fileName ); // ASE/LWO models
cm_model_t* LoadBinaryModel( const char* fileName, ID_TIME_T sourceTimeStamp );
cm_model_t* LoadBinaryModelFromFile( idFile* fileIn, ID_TIME_T sourceTimeStamp );
void WriteBinaryModel( cm_model_t* model, const char* fileName, ID_TIME_T sourceTimeStamp );
void WriteBinaryModelToFile( cm_model_t* model, idFile* fileOut, ID_TIME_T sourceTimeStamp );
bool TrmFromModel_r( idTraceModel& trm, cm_node_t* node );
bool TrmFromModel( const cm_model_t* model, idTraceModel& trm );
private: // CollisionMap_files.cpp
// writing
void WriteNodes( idFile* fp, cm_node_t* node );
int CountPolygonMemory( cm_node_t* node ) const;
void WritePolygons( idFile* fp, cm_node_t* node );
int CountBrushMemory( cm_node_t* node ) const;
void WriteBrushes( idFile* fp, cm_node_t* node );
void WriteCollisionModel( idFile* fp, cm_model_t* model );
void WriteCollisionModelsToFile( const char* filename, int firstModel, int lastModel, unsigned int mapFileCRC );
// loading
cm_node_t* ParseNodes( idLexer* src, cm_model_t* model, cm_node_t* parent );
void ParseVertices( idLexer* src, cm_model_t* model );
void ParseEdges( idLexer* src, cm_model_t* model );
void ParsePolygons( idLexer* src, cm_model_t* model );
void ParseBrushes( idLexer* src, cm_model_t* model );
cm_model_t* ParseCollisionModel( idLexer* src );
bool LoadCollisionModelFile( const char* name, unsigned int mapFileCRC );
private: // CollisionMap_debug
int ContentsFromString( const char* string ) const;
const char* StringFromContents( const int contents ) const;
void DrawEdge( cm_model_t* model, int edgeNum, const idVec3& origin, const idMat3& axis );
void DrawPolygon( cm_model_t* model, cm_polygon_t* p, const idVec3& origin, const idMat3& axis,
const idVec3& viewOrigin );
void DrawNodePolygons( cm_model_t* model, cm_node_t* node, const idVec3& origin, const idMat3& axis,
const idVec3& viewOrigin, const float radius );
private: // collision map data
idStr mapName;
ID_TIME_T mapFileTime;
int loaded;
// for multi-check avoidance
int checkCount;
// models
int maxModels;
int numModels;
cm_model_t** models;
// polygons and brush for trm model
cm_polygonRef_t* trmPolygons[MAX_TRACEMODEL_POLYS];
cm_brushRef_t* trmBrushes[1];
const idMaterial* trmMaterial;
// for data pruning
int numProcNodes;
cm_procNode_t* procNodes;
// for retrieving contact points
bool getContacts;
contactInfo_t* contacts;
int maxContacts;
int numContacts;
};
// for debugging
extern idCVar cm_debugCollision;