Collision Map Asset (MW2)
The collision map (or clip map) has existed on every Call of Duty so far and is part of the D3DBSP system produced by Radiant. Modern Warfare 2 has 2 clip map asset types (col_map_sp and col_map_mp) and they are loaded exactly the same.
/* dmaterial_t->contentFlags */
#define CONTENTS_NONE 0x0
#define CONTENTS_SOLID 0x1
#define CONTENTS_FOLIAGE 0x2
#define CONTENTS_AI_AVOID 0x4
#define CONTENTS_VEHICLETRIGGER 0x8
#define CONTENTS_GLASS 0x10
#define CONTENTS_WATER 0x20
#define CONTENTS_CANSHOOTCLIP 0x40
#define CONTENTS_CLIPMISSILE 0x80
#define CONTENTS_ITEM 0x100
#define CONTENTS_VEHICLECLIP 0x200
#define CONTENTS_ITEMCLIP 0x400
#define CONTENTS_SKY 0x800
#define CONTENTS_AI_NOSIGHT 0x1000
#define CONTENTS_CLIPSHOT 0x2000
#define CONTENTS_ACTOR 0x4000
#define CONTENTS_FAKE_ACTOR 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
#define CONTENTS_AXISTRIGGER 0x40000
#define CONTENTS_ALLIESTRIGGER 0x80000
#define CONTENTS_NEUTRALTRIGGER 0x100000
#define CONTENTS_USE 0x200000
#define CONTENTS_NONSENTIENTTRIGGER 0x400000
#define CONTENTS_VEHICLE 0x800000
#define CONTENTS_MANTLE 0x1000000
#define CONTENTS_PLAYER 0x2000000
#define CONTENTS_CORPSE 0x4000000
#define CONTENTS_DETAIL 0x8000000
#define CONTENTS_STRUCTURAL 0x10000000
#define CONTENTS_LOOKAT 0x20000000
#define CONTENTS_TRANSLUCENT 0x20000000
#define CONTENTS_PLAYERTRIGGER 0x40000000
#define CONTENTS_NODROP 0x80000000
/* dmaterial_t->surfaceFlags */
#define SURF_NODAMAGE 0x1
#define SURF_SLICK 0x2
#define SURF_SKY 0x4
#define SURF_LADDER 0x8
#define SURF_NOIMPACT 0x10
#define SURF_NOMARKS 0x20
#define SURF_HDRPORTAL 0x40
#define SURF_NODRAW 0x80
#define SURF_NOPENETRATE 0x100
#define SURF_STAIRS 0x200
#define SURF_NOLIGHTMAP 0x400
#define SURF_SOFT 0x1000
#define SURF_NOSTEPS 0x2000
#define SURF_NONSOLID 0x4000
#define SURF_NODLIGHT 0x20000
#define SURF_NOCASTSHADOW 0x40000
#define SURF_MANTLEOVER 0x1000000
#define SURF_MANTLEON 0x2000000
#define SURF_PORTAL 0x80000000
typedef char cbrushedge_t;
#pragma pack(push, 4)
struct cplane_s
{
float normal[3];
float dist;
char type;
char signbits;
};
struct cStaticModel_s
{
XModel *xmodel;
float origin[3];
float invScaledAxis[3][3];
float absmin[3];
float absmax[3];
};
struct dmaterial_t
{
char * material;
int surfaceFlags;
int contentFlags;
};
struct cbrushside_t
{
cplane_s *plane;
unsigned int materialNum;
};
struct cNode_t
{
cplane_s *plane;
__int16 children[2];
};
struct cLeaf_t
{
unsigned __int16 firstCollAabbIndex;
unsigned __int16 collAabbCount;
int brushContents;
int terrainContents;
float mins[3];
float maxs[3];
int leafBrushNode;
};
struct cLeafBrushNodeLeaf_t
{
unsigned __int16 *brushes;
};
struct cLeafBrushNodeChildren_t
{
float dist;
float range;
unsigned __int16 childOffset[6];
};
union cLeafBrushNodeData_t
{
cLeafBrushNodeLeaf_t leaf;
cLeafBrushNodeChildren_t children;
};
struct cLeafBrushNode_s
{
char axis;
__int16 leafBrushCount;
int contents;
cLeafBrushNodeData_t data;
};
struct CollisionBorder
{
float distEq[3];
float zBase;
float zSlope;
float start;
float length;
};
struct CollisionPartition
{
char triCount;
char borderCount;
int firstTri;
CollisionBorder *borders;
};
union CollisionAabbTreeIndex
{
int firstChildIndex;
int partitionIndex;
};
struct CollisionAabbTree
{
float origin[3];
float halfSize[3];
unsigned __int16 materialIndex;
unsigned __int16 childCount;
CollisionAabbTreeIndex u;
};
struct cmodel_t
{
float mins[3];
float maxs[3];
float radius;
cLeaf_t leaf;
};
struct cbrush_t
{
int contents;
cbrushside_t * sides;
cbrushedge_t * edge;
char unknown[0x18];
};
enum DynEntityType
{
DYNENT_TYPE_INVALID = 0x0,
DYNENT_TYPE_CLUTTER = 0x1,
DYNENT_TYPE_DESTRUCT = 0x2,
DYNENT_TYPE_COUNT = 0x3,
};
struct GfxPlacement
{
float quat[4];
float origin[3];
};
struct PhysMass
{
float centerOfMass[3];
float momentsOfInertia[3];
float productsOfInertia[3];
};
struct DynEntityDef
{
DynEntityType type;
GfxPlacement pose;
XModel *xModel;
unsigned __int16 brushModel;
unsigned __int16 physicsBrushModel;
FxEffectDef *destroyFx;
PhysPreset *physPreset;
int health;
PhysMass mass;
int contents;
};
struct DynEntityPose
{
GfxPlacement pose;
float radius;
};
struct DynEntityClient
{
int physObjId;
unsigned __int16 flags;
unsigned __int16 lightingHandle;
int health;
};
struct DynEntityColl
{
unsigned __int16 sector;
unsigned __int16 nextEntInSector;
float linkMins[2];
float linkMaxs[2];
};
struct clipMap_t
{
const char *name;
int unknown1;
int planeCount;
cplane_s *planes;
unsigned int numStaticModels;
cStaticModel_s *staticModelList;
unsigned int numMaterials;
dmaterial_t *materials;
unsigned int numBrushSides;
cbrushside_t *brushsides;
unsigned int numBrushEdges;
cbrushedge_t *brushEdges;
unsigned int numNodes;
cNode_t *nodes;
unsigned int numLeafs;
cLeaf_t *leafs;
unsigned int leafbrushNodesCount;
cLeafBrushNode_s *leafbrushNodes; //Leafbrushes loaded before this in FFs.
unsigned int numLeafBrushes;
unsigned __int16 *leafbrushes;
unsigned int numLeafSurfaces;
unsigned int *leafsurfaces;
unsigned int vertCount;
float (*verts)[3];
int triCount;
unsigned __int16 *triIndices;
char *triEdgeIsWalkable; //Size = ((triCount << 1) + triCount + 0x1F) >> 3 << 2
int borderCount;
CollisionBorder *borders;
int partitionCount;
CollisionPartition *partitions;
int aabbTreeCount;
CollisionAabbTree *aabbTrees;
unsigned int numSubModels;
cmodel_t *cmodels;
unsigned __int16 numBrushes;
cbrush_t *brushes;
char * unknown2; //Size = ((numBrushes << 1) + numBrushes) << 3
char * unknown3; //Size = numBrushes << 2
MapEnts *mapEnts;
unsigned __int16 unknownCount1;
char * unknown4; //Size = unknownCount1 * 0x1C
unsigned __int16 dynEntCount[2];
DynEntityDef *dynEntDefList[2];
DynEntityPose *dynEntPoseList[2];
DynEntityClient *dynEntClientList[2];
DynEntityColl *dynEntCollList[2];
char unknown5[0x30];
unsigned int checksum;
};
#pragma pack(pop)Keep in mind that the checksum is checked on other clients using the mapcrc dvar.
Source Format
The currently accepted source format is to dump the verticies and faces to "raw/maps/mp/(MAPNAME).d3dbsp.obj" because obj files are simple and easy to dump to. This clearly skips most of the clip map, so a more effiecient dumping method must be found.