/* =========================================================================== 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 . 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;