123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299 |
- // cmodel.c -- model loading
- #include "cm_local.h"
- #include "../RMG/RM_Headers.h"
- void CM_LoadShaderText(bool forceReload);
- #ifdef BSPC
- void SetPlaneSignbits (cplane_t *out) {
- int bits, j;
- // for fast box on planeside test
- bits = 0;
- for (j=0 ; j<3 ; j++) {
- if (out->normal[j] < 0) {
- bits |= 1<<j;
- }
- }
- out->signbits = bits;
- }
- #endif //BSPC
- // to allow boxes to be treated as brush models, we allocate
- // some extra indexes along with those needed by the map
- #define BOX_BRUSHES 1
- #define BOX_SIDES 6
- #define BOX_LEAFS 2
- #define BOX_PLANES 12
- #define LL(x) x=LittleLong(x)
- clipMap_t cmg;
- int c_pointcontents;
- int c_traces, c_brush_traces, c_patch_traces;
- byte *cmod_base;
- #ifndef BSPC
- cvar_t *cm_noAreas;
- cvar_t *cm_noCurves;
- cvar_t *cm_playerCurveClip;
- #endif
- cmodel_t box_model;
- cplane_t *box_planes;
- cbrush_t *box_brush;
- int CM_OrOfAllContentsFlagsInMap;
- void CM_InitBoxHull (void);
- void CM_FloodAreaConnections (clipMap_t &cm);
- clipMap_t SubBSP[MAX_SUB_BSP];
- int NumSubBSP = 0, TotalSubModels = 0;
- /*
- ===============================================================================
- MAP LOADING
- ===============================================================================
- */
- /*
- =================
- CMod_LoadShaders
- =================
- */
- void CMod_LoadShaders( lump_t *l, clipMap_t &cm )
- {
- dshader_t *in;
- int i, count;
- CCMShader *out;
- in = (dshader_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
- Com_Error (ERR_DROP, "CMod_LoadShaders: funny lump size");
- }
- count = l->filelen / sizeof(*in);
- if (count < 1) {
- Com_Error (ERR_DROP, "Map with no shaders");
- }
- cm.shaders = (CCMShader *)Z_Malloc( (1 + count) * sizeof( *cm.shaders ), TAG_BSP, qtrue ); //+1 for the BOX_SIDES to point at
- cm.numShaders = count;
- out = cm.shaders;
- for ( i = 0; i < count; i++, in++, out++ )
- {
- Q_strncpyz(out->shader, in->shader, MAX_QPATH);
- out->contentFlags = LittleLong( in->contentFlags );
- out->surfaceFlags = LittleLong( in->surfaceFlags );
- }
- }
- /*
- =================
- CMod_LoadSubmodels
- =================
- */
- void CMod_LoadSubmodels( lump_t *l, clipMap_t &cm ) {
- dmodel_t *in;
- cmodel_t *out;
- int i, j, count;
- int *indexes;
- in = (dmodel_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "CMod_LoadSubmodels: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 1) {
- Com_Error (ERR_DROP, "Map with no models");
- }
- //FIXME: note that MAX_SUBMODELS - 1 is used for BOX_MODEL_HANDLE, if that slot gets used, that would be bad, no?
- if ( count > MAX_SUBMODELS ) {
- Com_Error( ERR_DROP, "MAX_SUBMODELS (%d) exceeded by %d", MAX_SUBMODELS, count-MAX_SUBMODELS );
- }
- cm.cmodels = (struct cmodel_s *) Z_Malloc( count * sizeof( *cm.cmodels ), TAG_BSP, qtrue );
- cm.numSubModels = count;
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out = &cm.cmodels[i];
- for (j=0 ; j<3 ; j++)
- { // spread the mins / maxs by a pixel
- out->mins[j] = LittleFloat (in->mins[j]) - 1;
- out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
- }
- //rww - I changed this to do the &cm == &cmg check. sof2 does not have to do this,
- //but I think they have a different tracing system that allows it to catch subbsp
- //stuff without extra leaf data. The reason we have to do this for subbsp instances
- //is that they often are compiled in a sort of "prefab" form, so the first model isn't
- //necessarily the world model.
- if ( i == 0 && &cm == &cmg ) {
- continue; // world model doesn't need other info
- }
- // make a "leaf" just to hold the model's brushes and surfaces
- out->leaf.numLeafBrushes = LittleLong( in->numBrushes );
- indexes = (int *) Z_Malloc( out->leaf.numLeafBrushes * 4, TAG_BSP, qfalse);
- out->leaf.firstLeafBrush = indexes - cm.leafbrushes;
- for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {
- indexes[j] = LittleLong( in->firstBrush ) + j;
- }
- out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );
- indexes = (int *) Z_Malloc( out->leaf.numLeafSurfaces * 4, TAG_BSP, qfalse);
- out->leaf.firstLeafSurface = indexes - cm.leafsurfaces;
- for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {
- indexes[j] = LittleLong( in->firstSurface ) + j;
- }
- }
- }
- /*
- =================
- CMod_LoadNodes
- =================
- */
- void CMod_LoadNodes( lump_t *l, clipMap_t &cm ) {
- dnode_t *in;
- int child;
- cNode_t *out;
- int i, j, count;
-
- in = (dnode_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 1)
- Com_Error (ERR_DROP, "Map has no nodes");
- cm.nodes = (cNode_t *) Z_Malloc( count * sizeof( *cm.nodes ), TAG_BSP, qfalse);
- cm.numNodes = count;
- out = cm.nodes;
- for (i=0 ; i<count ; i++, out++, in++)
- {
- out->plane = cm.planes + LittleLong( in->planeNum );
- for (j=0 ; j<2 ; j++)
- {
- child = LittleLong (in->children[j]);
- out->children[j] = child;
- }
- }
- }
- /*
- =================
- CM_BoundBrush
- =================
- */
- void CM_BoundBrush( cbrush_t *b ) {
- b->bounds[0][0] = -b->sides[0].plane->dist;
- b->bounds[1][0] = b->sides[1].plane->dist;
- b->bounds[0][1] = -b->sides[2].plane->dist;
- b->bounds[1][1] = b->sides[3].plane->dist;
- b->bounds[0][2] = -b->sides[4].plane->dist;
- b->bounds[1][2] = b->sides[5].plane->dist;
- }
- /*
- =================
- CMod_LoadBrushes
- =================
- */
- void CMod_LoadBrushes( lump_t *l, clipMap_t &cm ) {
- dbrush_t *in;
- cbrush_t *out;
- int i, count;
- in = (dbrush_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- }
- count = l->filelen / sizeof(*in);
- cm.brushes = (cbrush_t *) Z_Malloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), TAG_BSP, qfalse);
- cm.numBrushes = count;
- out = cm.brushes;
- for ( i=0 ; i<count ; i++, out++, in++ ) {
- out->sides = cm.brushsides + LittleLong(in->firstSide);
- out->numsides = LittleLong(in->numSides);
- out->shaderNum = LittleLong( in->shaderNum );
- if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
- Com_Error( ERR_DROP, "CMod_LoadBrushes: bad shaderNum: %i", out->shaderNum );
- }
- out->contents = cm.shaders[out->shaderNum].contentFlags;
- CM_OrOfAllContentsFlagsInMap |= out->contents;
- out->checkcount=0;
- CM_BoundBrush( out );
- }
- }
- /*
- =================
- CMod_LoadLeafs
- =================
- */
- void CMod_LoadLeafs (lump_t *l, clipMap_t &cm)
- {
- int i;
- cLeaf_t *out;
- dleaf_t *in;
- int count;
-
- in = (dleaf_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no leafs");
- cm.leafs = (cLeaf_t *) Z_Malloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), TAG_BSP, qfalse);
- cm.numLeafs = count;
- out = cm.leafs;
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->cluster = LittleLong (in->cluster);
- out->area = LittleLong (in->area);
- out->firstLeafBrush = LittleLong (in->firstLeafBrush);
- out->numLeafBrushes = LittleLong (in->numLeafBrushes);
- out->firstLeafSurface = LittleLong (in->firstLeafSurface);
- out->numLeafSurfaces = LittleLong (in->numLeafSurfaces);
- if (out->cluster >= cm.numClusters)
- cm.numClusters = out->cluster + 1;
- if (out->area >= cm.numAreas)
- cm.numAreas = out->area + 1;
- }
- cm.areas = (cArea_t *) Z_Malloc( cm.numAreas * sizeof( *cm.areas ), TAG_BSP, qtrue );
- cm.areaPortals = (int *) Z_Malloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), TAG_BSP, qtrue );
- }
- /*
- =================
- CMod_LoadPlanes
- =================
- */
- void CMod_LoadPlanes (lump_t *l, clipMap_t &cm)
- {
- int i, j;
- cplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (dplane_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no planes");
- cm.planes = (struct cplane_s *) Z_Malloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), TAG_BSP, qfalse);
- cm.numPlanes = count;
- out = cm.planes;
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- bits = 0;
- for (j=0 ; j<3 ; j++)
- {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0)
- bits |= 1<<j;
- }
- out->dist = LittleFloat (in->dist);
- out->type = PlaneTypeForNormal( out->normal );
- out->signbits = bits;
- }
- }
- /*
- =================
- CMod_LoadLeafBrushes
- =================
- */
- void CMod_LoadLeafBrushes (lump_t *l, clipMap_t &cm)
- {
- int i;
- int *out;
- int *in;
- int count;
-
- in = (int *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- cm.leafbrushes = (int *) Z_Malloc( ( BOX_BRUSHES + count ) * sizeof( *cm.leafbrushes ), TAG_BSP, qfalse);
- cm.numLeafBrushes = count;
- out = cm.leafbrushes;
- for ( i=0 ; i<count ; i++, in++, out++) {
- *out = LittleLong (*in);
- }
- }
- /*
- =================
- CMod_LoadLeafSurfaces
- =================
- */
- void CMod_LoadLeafSurfaces( lump_t *l, clipMap_t &cm )
- {
- int i;
- int *out;
- int *in;
- int count;
-
- in = (int *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- cm.leafsurfaces = (int *) Z_Malloc( count * sizeof( *cm.leafsurfaces ), TAG_BSP, qfalse);
- cm.numLeafSurfaces = count;
- out = cm.leafsurfaces;
- for ( i=0 ; i<count ; i++, in++, out++) {
- *out = LittleLong (*in);
- }
- }
- /*
- =================
- CMod_LoadBrushSides
- =================
- */
- void CMod_LoadBrushSides (lump_t *l, clipMap_t &cm)
- {
- int i;
- cbrushside_t *out;
- dbrushside_t *in;
- int count;
- int num;
- in = (dbrushside_t *)(cmod_base + l->fileofs);
- if ( l->filelen % sizeof(*in) ) {
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- }
- count = l->filelen / sizeof(*in);
- cm.brushsides = (cbrushside_t *) Z_Malloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), TAG_BSP, qfalse);
- cm.numBrushSides = count;
- out = cm.brushsides;
- for ( i=0 ; i<count ; i++, in++, out++) {
- num = LittleLong( in->planeNum );
- out->plane = &cm.planes[num];
- out->shaderNum = LittleLong( in->shaderNum );
- if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
- Com_Error( ERR_DROP, "CMod_LoadBrushSides: bad shaderNum: %i", out->shaderNum );
- }
- // out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;
- }
- }
- /*
- =================
- CMod_LoadEntityString
- =================
- */
- void CMod_LoadEntityString( lump_t *l, clipMap_t &cm ) {
- cm.entityString = (char *) Z_Malloc( l->filelen, TAG_BSP, qfalse);
- cm.numEntityChars = l->filelen;
- memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);
- }
- /*
- =================
- CMod_LoadVisibility
- =================
- */
- #define VIS_HEADER 8
- void CMod_LoadVisibility( lump_t *l, clipMap_t &cm ) {
- int len;
- byte *buf;
- len = l->filelen;
- if ( !len ) {
- cm.clusterBytes = ( cm.numClusters + 31 ) & ~31;
- cm.visibility = (unsigned char *) Z_Malloc( cm.clusterBytes, TAG_BSP, qfalse);
- memset( cm.visibility, 255, cm.clusterBytes );
- return;
- }
- buf = cmod_base + l->fileofs;
- cm.vised = qtrue;
- cm.visibility = (unsigned char *) Z_Malloc( len, TAG_BSP, qtrue );
- cm.numClusters = LittleLong( ((int *)buf)[0] );
- cm.clusterBytes = LittleLong( ((int *)buf)[1] );
- memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );
- }
- //==================================================================
- /*
- =================
- CMod_LoadPatches
- =================
- */
- #define MAX_PATCH_VERTS 1024
- void CMod_LoadPatches( lump_t *surfs, lump_t *verts, clipMap_t &cm ) {
- mapVert_t *dv, *dv_p;
- dsurface_t *in;
- int count;
- int i, j;
- int c;
- cPatch_t *patch;
- vec3_t points[MAX_PATCH_VERTS];
- int width, height;
- int shaderNum;
- in = (dsurface_t *)(cmod_base + surfs->fileofs);
- if (surfs->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- cm.numSurfaces = count = surfs->filelen / sizeof(*in);
- cm.surfaces = (cPatch_t **) Z_Malloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), TAG_BSP, qtrue );
- dv = (mapVert_t *)(cmod_base + verts->fileofs);
- if (verts->filelen % sizeof(*dv))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- // scan through all the surfaces, but only load patches,
- // not planar faces
- for ( i = 0 ; i < count ; i++, in++ ) {
- if ( LittleLong( in->surfaceType ) != MST_PATCH ) {
- continue; // ignore other surfaces
- }
- // FIXME: check for non-colliding patches
- cm.surfaces[ i ] = patch = (cPatch_t *) Z_Malloc( sizeof( *patch ), TAG_BSP, qtrue );
- // load the full drawverts onto the stack
- width = LittleLong( in->patchWidth );
- height = LittleLong( in->patchHeight );
- c = width * height;
- if ( c > MAX_PATCH_VERTS ) {
- Com_Error( ERR_DROP, "ParseMesh: MAX_PATCH_VERTS" );
- }
- dv_p = dv + LittleLong( in->firstVert );
- for ( j = 0 ; j < c ; j++, dv_p++ ) {
- points[j][0] = LittleFloat( dv_p->xyz[0] );
- points[j][1] = LittleFloat( dv_p->xyz[1] );
- points[j][2] = LittleFloat( dv_p->xyz[2] );
- }
- shaderNum = LittleLong( in->shaderNum );
- patch->contents = cm.shaders[shaderNum].contentFlags;
- CM_OrOfAllContentsFlagsInMap |= patch->contents;
- patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;
- // create the internal facet structure
- patch->pc = CM_GeneratePatchCollide( width, height, points );
- }
- }
- //==================================================================
- #ifdef BSPC
- /*
- ==================
- CM_FreeMap
- Free any loaded map and all submodels
- ==================
- */
- void CM_FreeMap(void) {
- memset( &cm, 0, sizeof( cm ) );
- Hunk_ClearHigh();
- CM_ClearLevelPatches();
- }
- #endif //BSPC
- unsigned CM_LumpChecksum(lump_t *lump) {
- return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));
- }
- unsigned CM_Checksum(dheader_t *header) {
- unsigned checksums[16];
- checksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);
- checksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);
- checksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);
- checksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);
- checksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);
- checksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);
- checksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);
- checksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);
- checksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);
- checksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);
- checksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);
- return LittleLong(Com_BlockChecksum(checksums, 11 * 4));
- }
- /*
- ==================
- CM_LoadMap
- Loads in the map and all submodels
- ==================
- */
- void *gpvCachedMapDiskImage = NULL;
- char gsCachedMapDiskImage[MAX_QPATH];
- qboolean gbUsingCachedMapDataRightNow = qfalse; // if true, signifies that you can't delete this at the moment!! (used during z_malloc()-fail recovery attempt)
- // called in response to a "devmapbsp blah" or "devmapall blah" command, do NOT use inside CM_Load unless you pass in qtrue
- //
- // new bool return used to see if anything was freed, used during z_malloc failure re-try
- //
- qboolean CM_DeleteCachedMap(qboolean bGuaranteedOkToDelete)
- {
- qboolean bActuallyFreedSomething = qfalse;
- if (bGuaranteedOkToDelete || !gbUsingCachedMapDataRightNow)
- {
- // dump cached disk image...
- //
- if (gpvCachedMapDiskImage)
- {
- Z_Free( gpvCachedMapDiskImage );
- gpvCachedMapDiskImage = NULL;
- bActuallyFreedSomething = qtrue;
- }
- gsCachedMapDiskImage[0] = '\0';
-
- // force map loader to ignore cached internal BSP structures for next level CM_LoadMap() call...
- //
- cmg.name[0] = '\0';
- }
- return bActuallyFreedSomething;
- }
- static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *checksum, clipMap_t &cm ) {
- const int *buf;
- int i;
- dheader_t header;
- static unsigned last_checksum;
- void *subBSPData = NULL;
- if ( !name || !name[0] ) {
- Com_Error( ERR_DROP, "CM_LoadMap: NULL name" );
- }
- #ifndef BSPC
- cm_noAreas = Cvar_Get ("cm_noAreas", "0", CVAR_CHEAT);
- cm_noCurves = Cvar_Get ("cm_noCurves", "0", CVAR_CHEAT);
- cm_playerCurveClip = Cvar_Get ("cm_playerCurveClip", "1", CVAR_ARCHIVE|CVAR_CHEAT );
- #endif
- Com_DPrintf( "CM_LoadMap( %s, %i )\n", name, clientload );
- if ( !strcmp( cm.name, name ) && clientload ) {
- *checksum = last_checksum;
- return;
- }
- if (&cm == &cmg)
- {
- // if there was a cached disk image but the name was empty (ie ERR_DROP happened) or just doesn't match
- // the current name, then ditch it...
- //
- if (gpvCachedMapDiskImage &&
- (gsCachedMapDiskImage[0] == '\0' || strcmp( gsCachedMapDiskImage, name ))
- )
- {
- Z_Free(gpvCachedMapDiskImage);
- gpvCachedMapDiskImage = NULL;
- gsCachedMapDiskImage[0] = '\0';
- CM_ClearMap();
- }
- }
- // if there's a valid map name, and it's the same as last time (respawn?), and it's the server-load,
- // then keep the data from last time...
- //
- if (name[0] && !strcmp( cm.name, name ) && !clientload && &cm == &cmg )
- {
- // clear some stuff that needs zeroing...
- //
- cm.floodvalid = 0;
- //NO... don't reset this because the brush checkcounts are cached,
- //so when you load up, brush checkcounts equal the cm.checkcount
- //and the trace will be skipped (because everything loads and
- //traces in the same exact order ever time you load the map)
- cm.checkcount++;// = 0;
- memset(cm.areas, 0, cm.numAreas * sizeof( *cm.areas ));
- memset(cm.areaPortals, 0, cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ));
- }
- else
- {
- // ... else load map from scratch...
- //
- if (&cm == &cmg)
- {
- assert(!clientload); // logic check. I'm assuming that a client load doesn't get this far?
- // free old stuff
- memset( &cm, 0, sizeof( cm ) );
- CM_ClearLevelPatches();
- Z_TagFree(TAG_BSP);
- if ( !name[0] ) {
- cm.numLeafs = 1;
- cm.numClusters = 1;
- cm.numAreas = 1;
- cm.cmodels = (struct cmodel_s *) Z_Malloc( sizeof( *cm.cmodels ), TAG_BSP, qtrue );
- *checksum = 0;
- return;
- }
- }
- // load the file into a buffer that we either discard as usual at the bottom, or if we've got enough memory
- // then keep it long enough to save the renderer re-loading it, then discard it after that.
- //
- fileHandle_t h;
- const int iBSPLen = FS_FOpenFileRead( name, &h, qfalse );
- if(!h)
- {
- Com_Error (ERR_DROP, "Couldn't load %s", name);
- return;
- }
- //rww - only do this when not loading a sub-bsp!
- if (&cm == &cmg)
- {
- if (gpvCachedMapDiskImage && gsCachedMapDiskImage[0])
- { //didn't get cleared elsewhere so free it before we allocate the pointer again
- //Maps with terrain will allow this to happen because they want everything to be cleared out (going between terrain and no-terrain is messy)
- Z_Free(gpvCachedMapDiskImage);
- }
- gsCachedMapDiskImage[0] = '\0'; // flag that map isn't valid, until name is filled in
- gpvCachedMapDiskImage = Z_Malloc( iBSPLen, TAG_BSP_DISKIMAGE, qfalse);
- FS_Read(gpvCachedMapDiskImage, iBSPLen, h);
- FS_FCloseFile( h );
-
- buf = (int*) gpvCachedMapDiskImage; // so the rest of the code works as normal
- }
- else
- { //otherwise, read straight in..
- subBSPData = Z_Malloc( iBSPLen, TAG_BSP_DISKIMAGE, qfalse);
- FS_Read(subBSPData, iBSPLen, h);
- FS_FCloseFile( h );
- buf = (int*)subBSPData;
- }
- // carry on as before...
- last_checksum = LittleLong (Com_BlockChecksum (buf, iBSPLen));
- header = *(dheader_t *)buf;
- for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
- ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
- }
- if ( header.version != BSP_VERSION )
- {
- Z_Free( gpvCachedMapDiskImage);
- gpvCachedMapDiskImage = NULL;
- Com_Error (ERR_DROP, "CM_LoadMap: %s has wrong version number (%i should be %i)"
- , name, header.version, BSP_VERSION );
- }
- cmod_base = (byte *)buf;
- // load into heap
- CMod_LoadShaders( &header.lumps[LUMP_SHADERS], cm );
- CMod_LoadLeafs (&header.lumps[LUMP_LEAFS], cm);
- CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES], cm);
- CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES], cm);
- CMod_LoadPlanes (&header.lumps[LUMP_PLANES], cm);
- CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES], cm);
- CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES], cm);
- CMod_LoadSubmodels (&header.lumps[LUMP_MODELS], cm);
- CMod_LoadNodes (&header.lumps[LUMP_NODES], cm);
- CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES], cm);
- CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY], cm );
- CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS], cm );
- TotalSubModels += cm.numSubModels;
- // we are NOT freeing the file, because it is cached for the ref
- //actually we do because the new hunk sys won't allow it
- // actually we DON'T now <g>, if we've got enough ram to keep it for the renderer's disk-load...
- //
- extern qboolean Sys_LowPhysicalMemory();
- if (Sys_LowPhysicalMemory() //|| com_dedicated->integer // no need to check for dedicated in single-player codebase
- )
- {
- Z_Free( gpvCachedMapDiskImage );
- gpvCachedMapDiskImage = NULL;
- }
- else
- {
- // ... do nothing, and let the renderer free it after it's finished playing with it...
- //
- }
- if (subBSPData)
- {
- Z_Free(subBSPData);
- }
- if (&cm == &cmg)
- {
- #if !defined(BSPC)
- CM_LoadShaderText(false);
- // MAT_Init((bool)(!clientload));
- #endif
- CM_InitBoxHull ();
- #if !defined(BSPC)
- CM_SetupShaderProperties();
- #endif
- Q_strncpyz( gsCachedMapDiskImage, name, sizeof(gsCachedMapDiskImage) ); // so the renderer can check it
- }
- }
- *checksum = last_checksum;
- // do this whether or not the map was cached from last load...
- //
- CM_FloodAreaConnections (cm);
- // allow this to be cached if it is loaded by the server
- if ( !clientload ) {
- Q_strncpyz( cm.name, name, sizeof( cm.name ) );
- }
- CM_CleanLeafCache();
- }
- // need a wrapper function around this because of multiple returns, need to ensure bool is correct...
- //
- void CM_LoadMap( const char *name, qboolean clientload, int *checksum, qboolean subBSP )
- {
- if (subBSP)
- {
- CM_LoadSubBSP(va("maps/%s.bsp", ((const char *)name) + 1), qfalse);
- //CM_LoadMap_Actual( name, clientload, checksum, cmg );
- }
- else
- {
- gbUsingCachedMapDataRightNow = qtrue; // !!!!!!!!!!!!!!!!!!
- CM_LoadMap_Actual( name, clientload, checksum, cmg );
- gbUsingCachedMapDataRightNow = qfalse; // !!!!!!!!!!!!!!!!!!
- }
- /*
- gbUsingCachedMapDataRightNow = qtrue; // !!!!!!!!!!!!!!!!!!
- CM_LoadMap_Actual( name, clientload, checksum, cmg );
- gbUsingCachedMapDataRightNow = qfalse; // !!!!!!!!!!!!!!!!!!
- */
- }
- qboolean CM_SameMap(char *server)
- {
- if (!cmg.name[0] || !server || !server[0])
- {
- return qfalse;
- }
- if (Q_stricmp(cmg.name, va("maps/%s.bsp", server)))
- {
- return qfalse;
- }
- return qtrue;
- }
- qboolean CM_HasTerrain(void)
- {
- if (cmg.landScape)
- {
- return qtrue;
- }
- return qfalse;
- }
- /*
- ==================
- CM_ClearMap
- ==================
- */
- void CM_ClearMap( void )
- {
- int i;
- CM_OrOfAllContentsFlagsInMap = CONTENTS_BODY;
- #if !defined(BSPC)
- CM_ShutdownShaderProperties();
- // MAT_Shutdown();
- #endif
- if (TheRandomMissionManager)
- {
- delete TheRandomMissionManager;
- TheRandomMissionManager = 0;
- }
- if (cmg.landScape)
- {
- delete cmg.landScape;
- cmg.landScape = 0;
- }
- memset( &cmg, 0, sizeof( cmg ) );
- CM_ClearLevelPatches();
- for(i = 0; i < NumSubBSP; i++)
- {
- memset(&SubBSP[i], 0, sizeof(SubBSP[0]));
- }
- NumSubBSP = 0;
- TotalSubModels = 0;
- }
- int CM_TotalMapContents()
- {
- return CM_OrOfAllContentsFlagsInMap;
- }
- /*
- ==================
- CM_ClipHandleToModel
- ==================
- */
- cmodel_t *CM_ClipHandleToModel( clipHandle_t handle, clipMap_t **clipMap )
- {
- int i;
- int count;
- if ( handle < 0 )
- {
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle );
- }
- if ( handle < cmg.numSubModels )
- {
- if (clipMap)
- {
- *clipMap = &cmg;
- }
- return &cmg.cmodels[handle];
- }
- if ( handle == BOX_MODEL_HANDLE )
- {
- if (clipMap)
- {
- *clipMap = &cmg;
- }
- return &box_model;
- }
- count = cmg.numSubModels;
- for(i = 0; i < NumSubBSP; i++)
- {
- if (handle < count + SubBSP[i].numSubModels)
- {
- if (clipMap)
- {
- *clipMap = &SubBSP[i];
- }
- return &SubBSP[i].cmodels[handle - count];
- }
- count += SubBSP[i].numSubModels;
- }
- if ( handle < MAX_SUBMODELS )
- {
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i",
- cmg.numSubModels, handle, MAX_SUBMODELS );
- }
- Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS );
- return NULL;
- }
- /*
- ==================
- CM_InlineModel
- ==================
- */
- clipHandle_t CM_InlineModel( int index ) {
- if ( index < 0 || index >= TotalSubModels ) {
- Com_Error (ERR_DROP, "CM_InlineModel: bad number (may need to re-BSP map?)");
- }
- return index;
- }
- int CM_NumClusters( void ) {
- return cmg.numClusters;
- }
- int CM_NumInlineModels( void ) {
- return cmg.numSubModels;
- }
- char *CM_EntityString( void ) {
- return cmg.entityString;
- }
- char *CM_SubBSPEntityString( int index )
- {
- return SubBSP[index].entityString;
- }
- int CM_LeafCluster( int leafnum ) {
- if (leafnum < 0 || leafnum >= cmg.numLeafs) {
- Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
- }
- return cmg.leafs[leafnum].cluster;
- }
- int CM_LeafArea( int leafnum ) {
- if ( leafnum < 0 || leafnum >= cmg.numLeafs ) {
- Com_Error (ERR_DROP, "CM_LeafArea: bad number");
- }
- return cmg.leafs[leafnum].area;
- }
- //=======================================================================
- /*
- ===================
- CM_InitBoxHull
- Set up the planes and nodes so that the six floats of a bounding box
- can just be stored out and get a proper clipping hull structure.
- ===================
- */
- void CM_InitBoxHull (void)
- {
- int i;
- int side;
- cplane_t *p;
- cbrushside_t *s;
- box_planes = &cmg.planes[cmg.numPlanes];
- box_brush = &cmg.brushes[cmg.numBrushes];
- box_brush->numsides = 6;
- box_brush->sides = cmg.brushsides + cmg.numBrushSides;
- box_brush->contents = CONTENTS_BODY;
- box_model.leaf.numLeafBrushes = 1;
- // box_model.leaf.firstLeafBrush = cmg.numBrushes;
- box_model.leaf.firstLeafBrush = cmg.numLeafBrushes;
- cmg.leafbrushes[cmg.numLeafBrushes] = cmg.numBrushes;
- for (i=0 ; i<6 ; i++)
- {
- side = i&1;
- // brush sides
- s = &cmg.brushsides[cmg.numBrushSides+i];
- s->plane = cmg.planes + (cmg.numPlanes+i*2+side);
- s->shaderNum = cmg.numShaders; //not storing flags directly anymore, so be sure to point @ a valid shader
- // planes
- p = &box_planes[i*2];
- p->type = i>>1;
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = 1;
- p = &box_planes[i*2+1];
- p->type = 3 + (i>>1);
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = -1;
- SetPlaneSignbits( p );
- }
- }
- /*
- ===================
- CM_HeadnodeForBox
- To keep everything totally uniform, bounding boxes are turned into small
- BSP trees instead of being compared directly.
- ===================
- */
- clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs) {//, const int contents ) {
- box_planes[0].dist = maxs[0];
- box_planes[1].dist = -maxs[0];
- box_planes[2].dist = mins[0];
- box_planes[3].dist = -mins[0];
- box_planes[4].dist = maxs[1];
- box_planes[5].dist = -maxs[1];
- box_planes[6].dist = mins[1];
- box_planes[7].dist = -mins[1];
- box_planes[8].dist = maxs[2];
- box_planes[9].dist = -maxs[2];
- box_planes[10].dist = mins[2];
- box_planes[11].dist = -mins[2];
- VectorCopy( mins, box_brush->bounds[0] );
- VectorCopy( maxs, box_brush->bounds[1] );
- //FIXME: this is the "correct" way, but not the way JK2 was designed around... fix for further projects
- //box_brush->contents = contents;
- return BOX_MODEL_HANDLE;
- }
- /*
- ===================
- CM_ModelBounds
- ===================
- */
- void CM_ModelBounds( clipMap_t &cm, clipHandle_t model, vec3_t mins, vec3_t maxs )
- {
- cmodel_t *cmod;
- cmod = CM_ClipHandleToModel( model );
- VectorCopy( cmod->mins, mins );
- VectorCopy( cmod->maxs, maxs );
- }
- /*
- ===================
- CM_RegisterTerrain
- Allows physics to examine the terrain data.
- ===================
- */
- #if !defined(BSPC)
- CCMLandScape *CM_RegisterTerrain(const char *config, bool server)
- {
- thandle_t terrainId;
- CCMLandScape *ls;
- terrainId = atol(Info_ValueForKey(config, "terrainId"));
- if(terrainId && cmg.landScape)
- {
- // Already spawned so just return
- ls = cmg.landScape;
- ls->IncreaseRefCount();
- return(ls);
- }
- // Doesn't exist so create and link in
- //cmg.numTerrains++;
- ls = CM_InitTerrain(config, 1, server);
- // Increment for the next instance
- if (cmg.landScape)
- {
- Com_Error(ERR_DROP, "You can't have more than one terrain brush.");
- }
- cmg.landScape = ls;
- return(ls);
- }
- /*
- ===================
- CM_ShutdownTerrain
- ===================
- */
- void CM_ShutdownTerrain( thandle_t terrainId)
- {
- CCMLandScape *landscape;
- landscape = cmg.landScape;
- if (landscape)
- {
- landscape->DecreaseRefCount();
- if(landscape->GetRefCount() <= 0)
- {
- delete landscape;
- cmg.landScape = NULL;
- }
- }
- }
- #endif
- int CM_LoadSubBSP(const char *name, qboolean clientload)
- {
- int i;
- int checksum;
- int count;
- count = cmg.numSubModels;
- for(i = 0; i < NumSubBSP; i++)
- {
- if (!stricmp(name, SubBSP[i].name))
- {
- return count;
- }
- count += SubBSP[i].numSubModels;
- }
- if (NumSubBSP == MAX_SUB_BSP)
- {
- Com_Error (ERR_DROP, "CM_LoadSubBSP: too many unique sub BSPs");
- }
- CM_LoadMap_Actual( name, clientload, &checksum, SubBSP[NumSubBSP] );
- NumSubBSP++;
- return count;
- }
- int CM_FindSubBSP(int modelIndex)
- {
- int i;
- int count;
- count = cmg.numSubModels;
- if (modelIndex < count)
- { // belongs to the main bsp
- return -1;
- }
- for(i = 0; i < NumSubBSP; i++)
- {
- count += SubBSP[i].numSubModels;
- if (modelIndex < count)
- {
- return i;
- }
- }
- return -1;
- }
- void CM_GetWorldBounds ( vec3_t mins, vec3_t maxs )
- {
- VectorCopy ( cmg.cmodels[0].mins, mins );
- VectorCopy ( cmg.cmodels[0].maxs, maxs );
- }
- int CM_ModelContents_Actual( clipHandle_t model, clipMap_t *cm )
- {
- cmodel_t *cmod;
- int contents = 0;
- int i;
- if (!cm)
- {
- cm = &cmg;
- }
- cmod = CM_ClipHandleToModel( model, &cm );
- //MCG ADDED - return the contents, too
- if( cmod->leaf.numLeafBrushes ) // check for brush
- {
- int brushNum;
- for ( i = cmod->leaf.firstLeafBrush; i < cmod->leaf.firstLeafBrush+cmod->leaf.numLeafBrushes; i++ )
- {
- brushNum = cm->leafbrushes[i];
- contents |= cm->brushes[brushNum].contents;
- }
- }
- if( cmod->leaf.numLeafSurfaces ) // if not brush, check for patch
- {
- int surfaceNum;
- for ( i = cmod->leaf.firstLeafSurface; i < cmod->leaf.firstLeafSurface+cmod->leaf.numLeafSurfaces; i++ )
- {
- surfaceNum = cm->leafsurfaces[i];
- if ( cm->surfaces[surfaceNum] != NULL )
- {//HERNH? How could we have a null surf within our cmod->leaf.numLeafSurfaces?
- contents |= cm->surfaces[surfaceNum]->contents;
- }
- }
- }
- return contents;
- }
- int CM_ModelContents( clipHandle_t model, int subBSPIndex )
- {
- if (subBSPIndex < 0)
- {
- return CM_ModelContents_Actual(model, NULL);
- }
- return CM_ModelContents_Actual(model, &SubBSP[subBSPIndex]);
- }
- //support for save/load games
- /*
- ===================
- CM_WritePortalState
- Writes the portal state to a savegame file
- ===================
- */
- //
- qboolean SG_Append(unsigned long chid, const void *data, int length);
- int SG_Read(unsigned long chid, void *pvAddress, int iLength, void **ppvAddressPtr = NULL);
- void CM_WritePortalState ()
- {
- SG_Append('PRTS', (void *)cmg.areaPortals, cmg.numAreas * cmg.numAreas * sizeof( *cmg.areaPortals ));
- }
- /*
- ===================
- CM_ReadPortalState
- Reads the portal state from a savegame file
- and recalculates the area connections
- ===================
- */
- void CM_ReadPortalState ()
- {
- SG_Read('PRTS', (void *)cmg.areaPortals, cmg.numAreas * cmg.numAreas * sizeof( *cmg.areaPortals ));
- CM_FloodAreaConnections (cmg);
- }
|