--- quake2/qcommon/cmodel.c 2018/04/24 17:58:32 1.1 +++ quake2/qcommon/cmodel.c 2018/04/24 17:58:35 1.1.1.2 @@ -1,15 +1,19 @@ // cmodel.c -- model loading + #include "qcommon.h" + typedef struct { cplane_t *plane; int children[2]; // negative numbers are leafs } cnode_t; + typedef struct { cplane_t *plane; - csurface_t *surface; + mapsurface_t *surface; } cbrushside_t; + typedef struct { int contents; @@ -18,6 +22,7 @@ typedef struct unsigned short firstleafbrush; unsigned short numleafbrushes; } cleaf_t; + typedef struct { int contents; @@ -25,6 +30,7 @@ typedef struct int firstbrushside; int checkcount; // to avoid repeated testings } cbrush_t; + typedef struct { int numareaportals; @@ -32,49 +38,78 @@ typedef struct int floodnum; // if two areas have equal floodnums, they are connected int floodvalid; } carea_t; + int checkcount; + char map_name[MAX_QPATH]; + int numbrushsides; cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES]; + int numtexinfo; -csurface_t map_surfaces[MAX_MAP_TEXINFO]; +mapsurface_t map_surfaces[MAX_MAP_TEXINFO]; + int numplanes; cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull + int numnodes; cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull + int numleafs = 1; // allow leaf funcs to be called without a map cleaf_t map_leafs[MAX_MAP_LEAFS]; int emptyleaf, solidleaf; + int numleafbrushes; unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; + int numcmodels; cmodel_t map_cmodels[MAX_MAP_MODELS]; + int numbrushes; cbrush_t map_brushes[MAX_MAP_BRUSHES]; + int numvisibility; byte map_visibility[MAX_MAP_VISIBILITY]; dvis_t *map_vis = (dvis_t *)map_visibility; + int numentitychars; char map_entitystring[MAX_MAP_ENTSTRING]; + int numareas = 1; carea_t map_areas[MAX_MAP_AREAS]; + int numareaportals; dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; + int numclusters = 1; -csurface_t nullsurface; + +mapsurface_t nullsurface; + int floodvalid; + qboolean portalopen[MAX_MAP_AREAPORTALS]; + + cvar_t *map_noareas; + void CM_InitBoxHull (void); void FloodAreaConnections (void); + + int c_pointcontents; int c_traces, c_brush_traces; + + /* =============================================================================== + MAP LOADING + =============================================================================== */ + byte *cmod_base; + /* ================= CMod_LoadSubmodels @@ -85,18 +120,23 @@ void CMod_LoadSubmodels (lump_t *l) dmodel_t *in; cmodel_t *out; int i, j, count; + in = (void *)(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 models"); if (count > MAX_MAP_MODELS) Com_Error (ERR_DROP, "Map has too many models"); + numcmodels = count; + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; @@ -106,6 +146,8 @@ void CMod_LoadSubmodels (lump_t *l) out->headnode = LittleLong (in->headnode); } } + + /* ================= CMod_LoadSurfaces @@ -114,8 +156,9 @@ CMod_LoadSurfaces void CMod_LoadSurfaces (lump_t *l) { texinfo_t *in; - csurface_t *out; + mapsurface_t *out; int i, count; + in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); @@ -124,18 +167,24 @@ void CMod_LoadSurfaces (lump_t *l) Com_Error (ERR_DROP, "Map with no surfaces"); if (count > MAX_MAP_TEXINFO) Com_Error (ERR_DROP, "Map has too many surfaces"); + numtexinfo = count; out = map_surfaces; + for ( i=0 ; iname, in->texture, sizeof(out->name)-1); - out->flags = LittleLong (in->flags); - out->value = LittleLong (in->value); + strncpy (out->c.name, in->texture, sizeof(out->c.name)-1); + strncpy (out->rname, in->texture, sizeof(out->rname)-1); + out->c.flags = LittleLong (in->flags); + out->c.value = LittleLong (in->value); } } + + /* ================= CMod_LoadNodes + ================= */ void CMod_LoadNodes (lump_t *l) @@ -149,12 +198,16 @@ void CMod_LoadNodes (lump_t *l) 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"); if (count > MAX_MAP_NODES) Com_Error (ERR_DROP, "Map has too many nodes"); + out = map_nodes; + numnodes = count; + for (i=0 ; iplane = map_planes + LittleLong(in->planenum); @@ -164,10 +217,13 @@ void CMod_LoadNodes (lump_t *l) out->children[j] = child; } } + } + /* ================= CMod_LoadBrushes + ================= */ void CMod_LoadBrushes (lump_t *l) @@ -180,17 +236,23 @@ void CMod_LoadBrushes (lump_t *l) if (l->filelen % sizeof(*in)) Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); count = l->filelen / sizeof(*in); + if (count > MAX_MAP_BRUSHES) Com_Error (ERR_DROP, "Map has too many brushes"); + out = map_brushes; + numbrushes = count; + for (i=0 ; ifirstbrushside = LittleLong(in->firstside); out->numsides = LittleLong(in->numsides); out->contents = LittleLong(in->contents); } + } + /* ================= CMod_LoadLeafs @@ -207,14 +269,17 @@ void CMod_LoadLeafs (lump_t *l) 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"); // need to save space for box planes if (count > MAX_MAP_PLANES) Com_Error (ERR_DROP, "Map has too many planes"); + out = map_leafs; numleafs = count; numclusters = 0; + for ( i=0 ; icontents = LittleLong (in->contents); @@ -222,9 +287,11 @@ void CMod_LoadLeafs (lump_t *l) out->area = LittleShort (in->area); out->firstleafbrush = LittleShort (in->firstleafbrush); out->numleafbrushes = LittleShort (in->numleafbrushes); + if (out->cluster >= numclusters) numclusters = out->cluster + 1; } + if (map_leafs[0].contents != CONTENTS_SOLID) Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); solidleaf = 0; @@ -240,6 +307,7 @@ void CMod_LoadLeafs (lump_t *l) if (emptyleaf == -1) Com_Error (ERR_DROP, "Map does not have an empty leaf"); } + /* ================= CMod_LoadPlanes @@ -257,13 +325,16 @@ void CMod_LoadPlanes (lump_t *l) 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"); // need to save space for box planes if (count > MAX_MAP_PLANES) Com_Error (ERR_DROP, "Map has too many planes"); + out = map_planes; numplanes = count; + for ( i=0 ; inormal[j] < 0) bits |= 1<dist = LittleFloat (in->dist); out->type = LittleLong (in->type); out->signbits = bits; } } + /* ================= CMod_LoadLeafBrushes @@ -294,16 +367,20 @@ void CMod_LoadLeafBrushes (lump_t *l) 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"); // need to save space for box planes if (count > MAX_MAP_LEAFBRUSHES) Com_Error (ERR_DROP, "Map has too many leafbrushes"); + out = map_leafbrushes; numleafbrushes = count; + for ( i=0 ; ifileofs); if (l->filelen % sizeof(*in)) Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size"); count = l->filelen / sizeof(*in); + // need to save space for box planes if (count > MAX_MAP_BRUSHSIDES) Com_Error (ERR_DROP, "Map has too many planes"); + out = map_brushsides; numbrushsides = count; + for ( i=0 ; iplanenum); @@ -335,6 +416,7 @@ void CMod_LoadBrushSides (lump_t *l) out->surface = &map_surfaces[j]; } } + /* ================= CMod_LoadAreas @@ -346,14 +428,18 @@ void CMod_LoadAreas (lump_t *l) carea_t *out; darea_t *in; int count; + in = (void *)(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 > MAX_MAP_AREAS) Com_Error (ERR_DROP, "Map has too many areas"); + out = map_areas; numareas = count; + for ( i=0 ; inumareaportals = LittleLong (in->numareaportals); @@ -362,6 +448,7 @@ void CMod_LoadAreas (lump_t *l) out->floodnum = 0; } } + /* ================= CMod_LoadAreaPortals @@ -373,20 +460,25 @@ void CMod_LoadAreaPortals (lump_t *l) dareaportal_t *out; dareaportal_t *in; int count; + in = (void *)(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 > MAX_MAP_AREAS) Com_Error (ERR_DROP, "Map has too many areas"); + out = map_areaportals; numareaportals = count; + for ( i=0 ; iportalnum = LittleLong (in->portalnum); out->otherarea = LittleLong (in->otherarea); } } + /* ================= CMod_LoadVisibility @@ -395,10 +487,13 @@ CMod_LoadVisibility void CMod_LoadVisibility (lump_t *l) { int i; + numvisibility = l->filelen; if (l->filelen > MAX_MAP_VISIBILITY) Com_Error (ERR_DROP, "Map has too large visibility lump"); + memcpy (map_visibility, cmod_base + l->fileofs, l->filelen); + map_vis->numclusters = LittleLong (map_vis->numclusters); for (i=0 ; inumclusters ; i++) { @@ -406,6 +501,8 @@ void CMod_LoadVisibility (lump_t *l) map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]); } } + + /* ================= CMod_LoadEntityString @@ -416,11 +513,16 @@ void CMod_LoadEntityString (lump_t *l) numentitychars = l->filelen; if (l->filelen > MAX_MAP_ENTSTRING) Com_Error (ERR_DROP, "Map has too large entity lump"); + memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen); } + + + /* ================== CM_LoadMap + Loads in the map and all submodels ================== */ @@ -431,7 +533,9 @@ cmodel_t *CM_LoadMap (char *name, qboole dheader_t header; int length; static unsigned last_checksum; + map_noareas = Cvar_Get ("map_noareas", "0", 0); + if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) ) { *checksum = last_checksum; @@ -442,6 +546,7 @@ cmodel_t *CM_LoadMap (char *name, qboole } return &map_cmodels[0]; // still have the right version } + // free old stuff numplanes = 0; numnodes = 0; @@ -451,6 +556,7 @@ cmodel_t *CM_LoadMap (char *name, qboole numentitychars = 0; map_entitystring[0] = 0; map_name[0] = 0; + if (!name || !name[0]) { numleafs = 1; @@ -459,6 +565,7 @@ cmodel_t *CM_LoadMap (char *name, qboole *checksum = 0; return &map_cmodels[0]; // cinematic servers won't have anything at all } + // // load the file // @@ -468,13 +575,17 @@ cmodel_t *CM_LoadMap (char *name, qboole last_checksum = LittleLong (Com_BlockChecksum (buf, length)); *checksum = last_checksum; + header = *(dheader_t *)buf; for (i=0 ; i= numcmodels) Com_Error (ERR_DROP, "CM_InlineModel: bad number"); + return &map_cmodels[num]; } + int CM_NumClusters (void) { return numclusters; } + int CM_NumInlineModels (void) { return numcmodels; } + char *CM_EntityString (void) { return map_entitystring; } + int CM_LeafContents (int leafnum) { if (leafnum < 0 || leafnum >= numleafs) Com_Error (ERR_DROP, "CM_LeafContents: bad number"); return map_leafs[leafnum].contents; } + int CM_LeafCluster (int leafnum) { if (leafnum < 0 || leafnum >= numleafs) Com_Error (ERR_DROP, "CM_LeafCluster: bad number"); return map_leafs[leafnum].cluster; } + int CM_LeafArea (int leafnum) { if (leafnum < 0 || leafnum >= numleafs) Com_Error (ERR_DROP, "CM_LeafArea: bad number"); return map_leafs[leafnum].area; } + //======================================================================= + + cplane_t *box_planes; int box_headnode; cbrush_t *box_brush; cleaf_t *box_leaf; + /* =================== 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. =================== @@ -559,6 +689,7 @@ void CM_InitBoxHull (void) cnode_t *c; cplane_t *p; cbrushside_t *s; + box_headnode = numnodes; box_planes = &map_planes[numplanes]; if (numnodes+6 > MAX_MAP_NODES @@ -567,22 +698,28 @@ void CM_InitBoxHull (void) || numbrushsides+6 > MAX_MAP_BRUSHSIDES || numplanes+12 > MAX_MAP_PLANES) Com_Error (ERR_DROP, "Not enough room for box tree"); + box_brush = &map_brushes[numbrushes]; box_brush->numsides = 6; box_brush->firstbrushside = numbrushsides; box_brush->contents = CONTENTS_MONSTER; + box_leaf = &map_leafs[numleafs]; box_leaf->contents = CONTENTS_MONSTER; box_leaf->firstleafbrush = numleafbrushes; box_leaf->numleafbrushes = 1; + map_leafbrushes[numleafbrushes] = numbrushes; + for (i=0 ; i<6 ; i++) { side = i&1; + // brush sides s = &map_brushsides[numbrushsides+i]; s->plane = map_planes + (numplanes+i*2+side); s->surface = &nullsurface; + // nodes c = &map_nodes[box_headnode+i]; c->plane = map_planes + (numplanes+i*2); @@ -591,12 +728,14 @@ void CM_InitBoxHull (void) c->children[side^1] = box_headnode+i + 1; else c->children[side^1] = -1 - numleafs; + // 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; @@ -604,9 +743,12 @@ void CM_InitBoxHull (void) p->normal[i>>1] = -1; } } + + /* =================== CM_HeadnodeForBox + To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being compared directly. =================== @@ -625,11 +767,15 @@ int CM_HeadnodeForBox (vec3_t mins, vec3 box_planes[9].dist = -maxs[2]; box_planes[10].dist = mins[2]; box_planes[11].dist = -mins[2]; + return box_headnode; } + + /* ================== CM_PointLeafnum_r + ================== */ int CM_PointLeafnum_r (vec3_t p, int num) @@ -637,6 +783,7 @@ int CM_PointLeafnum_r (vec3_t p, int num float d; cnode_t *node; cplane_t *plane; + while (num >= 0) { node = map_nodes + num; @@ -651,18 +798,25 @@ int CM_PointLeafnum_r (vec3_t p, int num else num = node->children[0]; } + c_pointcontents++; // optimize counter + return -1 - num; } + int CM_PointLeafnum (vec3_t p) { if (!numplanes) return 0; // sound may call this without map loaded return CM_PointLeafnum_r (p, 0); } + + + /* ============= CM_BoxLeafnums + Fills in a list of all the leafs touched ============= */ @@ -670,11 +824,13 @@ int leaf_count, leaf_maxcount; int *leaf_list; float *leaf_mins, *leaf_maxs; int leaf_topnode; + void CM_BoxLeafnums_r (int nodenum) { cplane_t *plane; cnode_t *node; int s; + while (1) { if (nodenum < 0) @@ -703,8 +859,10 @@ void CM_BoxLeafnums_r (int nodenum) CM_BoxLeafnums_r (node->children[0]); nodenum = node->children[1]; } + } } + int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode) { leaf_list = list; @@ -712,34 +870,47 @@ int CM_BoxLeafnums_headnode (vec3_t mins leaf_maxcount = listsize; leaf_mins = mins; leaf_maxs = maxs; + leaf_topnode = -1; + CM_BoxLeafnums_r (headnode); + if (topnode) *topnode = leaf_topnode; + return leaf_count; } + int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode) { return CM_BoxLeafnums_headnode (mins, maxs, list, listsize, map_cmodels[0].headnode, topnode); } + + + /* ================== CM_PointContents + ================== */ int CM_PointContents (vec3_t p, int headnode) { int l; + if (!numnodes) // map not loaded return 0; l = CM_PointLeafnum_r (p, headnode); + return map_leafs[l].contents; } + /* ================== CM_TransformedPointContents + Handles offseting and rotation of the end points for moving and rotating entities ================== @@ -750,34 +921,47 @@ int CM_TransformedPointContents (vec3_t vec3_t temp; vec3_t forward, right, up; int l; + // subtract origin offset VectorSubtract (p, origin, p_l); + // rotate start and end into the models frame of reference if (headnode != box_headnode && (angles[0] || angles[1] || angles[2]) ) { AngleVectors (angles, forward, right, up); + VectorCopy (p_l, temp); p_l[0] = DotProduct (temp, forward); p_l[1] = -DotProduct (temp, right); p_l[2] = DotProduct (temp, up); } + l = CM_PointLeafnum_r (p_l, headnode); + return map_leafs[l].contents; } + + /* =============================================================================== + BOX TRACING + =============================================================================== */ + // 1/32 epsilon to keep floating point happy #define DIST_EPSILON (0.03125) + vec3_t trace_start, trace_end; vec3_t trace_mins, trace_maxs; vec3_t trace_extents; + trace_t trace_trace; int trace_contents; qboolean trace_ispoint; // optimized case + /* ================ CM_ClipBoxToBrush @@ -886,7 +1070,7 @@ void CM_ClipBoxToBrush (vec3_t mins, vec enterfrac = 0; trace->fraction = enterfrac; trace->plane = *clipplane; - trace->surface = leadside->surface; + trace->surface = &(leadside->surface->c); trace->contents = brush->contents; } } @@ -946,6 +1130,7 @@ void CM_TestBoxInBrush (vec3_t mins, vec trace->contents = brush->contents; } + /* ================ CM_TraceToLeaf @@ -1017,6 +1202,7 @@ void CM_TestInLeaf (int leafnum) /* ================== CM_RecursiveHullCheck + ================== */ void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2) @@ -1030,20 +1216,24 @@ void CM_RecursiveHullCheck (int num, flo vec3_t mid; int side; float midf; + if (trace_trace.fraction <= p1f) return; // already hit something nearer + // if < 0, we are in a leaf node if (num < 0) { CM_TraceToLeaf (-1-num); return; } + // // find the point distances to the seperating plane // and the offset for the size of the box // node = map_nodes + num; plane = node->plane; + if (plane->type < 3) { t1 = p1[plane->type] - plane->dist; @@ -1061,11 +1251,14 @@ void CM_RecursiveHullCheck (int num, flo fabs(trace_extents[1]*plane->normal[1]) + fabs(trace_extents[2]*plane->normal[2]); } + + #if 0 CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2); CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); return; #endif + // see which sides we need to consider if (t1 >= offset && t2 >= offset) { @@ -1077,6 +1270,7 @@ return; CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); return; } + // put the crosspoint DIST_EPSILON pixels on the near side if (t1 < t2) { @@ -1098,6 +1292,7 @@ return; frac = 1; frac2 = 0; } + // move up to the node if (frac < 0) frac = 0; @@ -1107,7 +1302,10 @@ return; midf = p1f + (p2f - p1f)*frac; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac*(p2[i] - p1[i]); + CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid); + + // go past the node if (frac2 < 0) frac2 = 0; @@ -1117,9 +1315,14 @@ return; midf = p1f + (p2f - p1f)*frac2; for (i=0 ; i<3 ; i++) mid[i] = p1[i] + frac2*(p2[i] - p1[i]); + CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2); } + + + //====================================================================== + /* ================== CM_BoxTrace @@ -1130,15 +1333,19 @@ trace_t CM_BoxTrace (vec3_t start, vec3 int headnode, int brushmask) { int i; + checkcount++; // for multi-check avoidance + c_traces++; // for statistics, may be zeroed + // fill in a default trace memset (&trace_trace, 0, sizeof(trace_trace)); trace_trace.fraction = 1; - trace_trace.surface = &nullsurface; + trace_trace.surface = &(nullsurface.c); if (!numnodes) // map not loaded return trace_trace; + trace_contents = brushmask; VectorCopy (start, trace_start); VectorCopy (end, trace_end); @@ -1195,6 +1402,7 @@ trace_t CM_BoxTrace (vec3_t start, vec3 // general sweeping through world // CM_RecursiveHullCheck (headnode, 0, 1, start, end); + if (trace_trace.fraction == 1) { VectorCopy (end, trace_trace.endpos); @@ -1206,9 +1414,12 @@ trace_t CM_BoxTrace (vec3_t start, vec3 } return trace_trace; } + + /* ================== CM_TransformedBoxTrace + Handles offseting and rotation of the end points for moving and rotating entities ================== @@ -1229,54 +1440,69 @@ trace_t CM_TransformedBoxTrace (vec3_t vec3_t forward, right, up; vec3_t temp; qboolean rotated; + // subtract origin offset VectorSubtract (start, origin, start_l); VectorSubtract (end, origin, end_l); + // rotate start and end into the models frame of reference if (headnode != box_headnode && (angles[0] || angles[1] || angles[2]) ) rotated = true; else rotated = false; + if (rotated) { AngleVectors (angles, forward, right, up); + VectorCopy (start_l, temp); start_l[0] = DotProduct (temp, forward); start_l[1] = -DotProduct (temp, right); start_l[2] = DotProduct (temp, up); + VectorCopy (end_l, temp); end_l[0] = DotProduct (temp, forward); end_l[1] = -DotProduct (temp, right); end_l[2] = DotProduct (temp, up); } + // sweep the box through the model trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask); + if (rotated && trace.fraction != 1.0) { // FIXME: figure out how to do this with existing angles VectorNegate (angles, a); AngleVectors (a, forward, right, up); + VectorCopy (trace.plane.normal, temp); trace.plane.normal[0] = DotProduct (temp, forward); trace.plane.normal[1] = -DotProduct (temp, right); trace.plane.normal[2] = DotProduct (temp, up); } + trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); + return trace; } + #ifdef _WIN32 #pragma optimize( "", on ) #endif + /* =============================================================================== + PVS / PHS + =============================================================================== */ + /* =================== CM_DecompressVis @@ -1287,6 +1513,7 @@ void CM_DecompressVis (byte *in, byte *o int c; byte *out_p; int row; + row = (numclusters+7)>>3; out_p = out; @@ -1299,6 +1526,7 @@ void CM_DecompressVis (byte *in, byte *o } return; } + do { if (*in) @@ -1321,8 +1549,10 @@ void CM_DecompressVis (byte *in, byte *o } } while (out_p - out < row); } + byte pvsrow[MAX_MAP_LEAFS/8]; byte phsrow[MAX_MAP_LEAFS/8]; + byte *CM_ClusterPVS (int cluster) { if (cluster == -1) @@ -1331,6 +1561,7 @@ byte *CM_ClusterPVS (int cluster) CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow); return pvsrow; } + byte *CM_ClusterPHS (int cluster) { if (cluster == -1) @@ -1339,21 +1570,28 @@ byte *CM_ClusterPHS (int cluster) CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow); return phsrow; } + + /* =============================================================================== + AREAPORTALS + =============================================================================== */ + void FloodArea_r (carea_t *area, int floodnum) { int i; dareaportal_t *p; + if (area->floodvalid == floodvalid) { if (area->floodnum == floodnum) return; Com_Error (ERR_DROP, "FloodArea_r: reflooded"); } + area->floodnum = floodnum; area->floodvalid = floodvalid; p = &map_areaportals[area->firstareaportal]; @@ -1363,9 +1601,12 @@ void FloodArea_r (carea_t *area, int flo FloodArea_r (&map_areas[p->otherarea], floodnum); } } + /* ==================== FloodAreaConnections + + ==================== */ void FloodAreaConnections (void) @@ -1373,9 +1614,11 @@ void FloodAreaConnections (void) int i; carea_t *area; int floodnum; + // all current floods are now invalid floodvalid++; floodnum = 0; + // area 0 is not used for (i=1 ; i numareaportals) Com_Error (ERR_DROP, "areaportal > numareaportals"); + portalopen[portalnum] = open; FloodAreaConnections (); } + qboolean CM_AreasConnected (int area1, int area2) { if (map_noareas->value) return true; + if (area1 > numareas || area2 > numareas) Com_Error (ERR_DROP, "area > numareas"); + if (map_areas[area1].floodnum == map_areas[area2].floodnum) return true; return false; } + + /* ================= CM_WriteAreaBits + Writes a length byte followed by a bit vector of all the areas that area in the same flood as the area parameter + This is used by the client refreshes to cull visibility ================= */ @@ -1416,7 +1669,9 @@ int CM_WriteAreaBits (byte *buffer, int int i; int floodnum; int bytes; + bytes = (numareas+7)>>3; + if (map_noareas->value) { // for debugging, send everything memset (buffer, 255, bytes); @@ -1424,6 +1679,7 @@ int CM_WriteAreaBits (byte *buffer, int else { memset (buffer, 0, bytes); + floodnum = map_areas[area].floodnum; for (i=0 ; i>3] |= 1<<(i&7); } } + return bytes; } + + /* =================== CM_WritePortalState + Writes the portal state to a savegame file =================== */ @@ -1443,9 +1703,11 @@ void CM_WritePortalState (FILE *f) { fwrite (portalopen, sizeof(portalopen), 1, f); } + /* =================== CM_ReadPortalState + Reads the portal state from a savegame file and recalculates the area connections =================== @@ -1455,9 +1717,11 @@ void CM_ReadPortalState (FILE *f) FS_Read (portalopen, sizeof(portalopen), f); FloodAreaConnections (); } + /* ============= CM_HeadnodeVisible + Returns true if any leaf under headnode has a cluster that is potentially visible ============= @@ -1467,6 +1731,7 @@ qboolean CM_HeadnodeVisible (int nodenum int leafnum; int cluster; cnode_t *node; + if (nodenum < 0) { leafnum = -1-nodenum; @@ -1477,8 +1742,10 @@ qboolean CM_HeadnodeVisible (int nodenum return true; return false; } + node = &map_nodes[nodenum]; if (CM_HeadnodeVisible(node->children[0], visbits)) return true; return CM_HeadnodeVisible(node->children[1], visbits); } +