diff --git a/Makefile b/Makefile index 17eb93a9..a6b8d7c0 100644 --- a/Makefile +++ b/Makefile @@ -195,10 +195,14 @@ CLIENT_OBJS = \ # Common objects COMMON_OBJS = \ + build/common/cm_areaportals.o \ + build/common/cm_box.o \ + build/common/cm_boxtracing.o \ + build/common/cm_bsp.o \ + build/common/cm_vis.o \ build/common/co_cmdexecution.o \ build/common/co_cmdparser.o \ build/common/co_cmdscript.o \ - build/common/cmodel.o \ build/common/common.o \ build/common/crc.o \ build/common/cvar.o \ @@ -269,10 +273,14 @@ DEDICATED_SERVER_OBJS = \ # Dedicated server common objects DEDICATED_SERVER_COMMON_OBJS = \ + build/dedicated_server_common/cm_areaportals.o \ + build/dedicated_server_common/cm_box.o \ + build/dedicated_server_common/cm_boxtracing.o \ + build/dedicated_server_common/cm_bsp.o \ + build/dedicated_server_common/cm_vis.o \ build/dedicated_server_common/co_cmdexecution.o \ build/dedicated_server_common/co_cmdparser.o \ build/dedicated_server_common/co_cmdscript.o \ - build/dedicated_server_common/cmodel.o \ build/dedicated_server_common/common.o \ build/dedicated_server_common/crc.o \ build/dedicated_server_common/cvar.o \ @@ -481,17 +489,32 @@ build/client/sound/snd_wav.o : src/client/sound/snd_wav.c # --------- -# Common build +# Common build +build/common/cm_areaportals.o : src/common/cm_areaportals.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + +build/common/cm_box.o : src/common/cm_box.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + +build/common/cm_boxtracing.o : src/common/cm_boxtracing.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + +build/common/cm_bsp.o : src/common/cm_bsp.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + +build/common/cm_vis.o : src/common/cm_vis.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + +build/common/cm_.o : src/common/cm_.c + $(CC) $(CFLAGS_CLIENT) -o $@ -c $< + build/common/co_cmdexecution.o : src/common/co_cmdexecution.c $(CC) $(CFLAGS_CLIENT) -o $@ -c $< -build/common/co_cmdparser.o : src/common/co_cmdparser.c +build/common/co_cmdparser.o : src/common/co_cmdparser.c $(CC) $(CFLAGS_CLIENT) -o $@ -c $< -build/common/co_cmdscript.o : src/common/co_cmdscript.c - $(CC) $(CFLAGS_CLIENT) -o $@ -c $< - -build/common/cmodel.o : src/common/cmodel.c +build/common/co_cmdscript.o : src/common/co_cmdscript.c $(CC) $(CFLAGS_CLIENT) -o $@ -c $< build/common/common.o : src/common/common.c @@ -617,38 +640,51 @@ build/dedicated_server/sv_world.o : src/server/sv_world.c # --------- -# Dedicated server common build +# Dedicated server common build + +build/dedicated_server_common/cm_areaportals.o : src/common/cm_areaportals.c + $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< + +build/dedicated_server_common/cm_box.o : src/common/cm_box.c + $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< + +build/dedicated_server_common/cm_boxtracing.o : src/common/cm_boxtracing.c + $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< + +build/dedicated_server_common/cm_bsp.o : src/common/cm_bsp.c + $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< + +build/dedicated_server_common/cm_vis.o : src/common/cm_vis.c + $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< + build/dedicated_server_common/co_cmdexecution.o : src/common/co_cmdexecution.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/co_cmdparser.o : src/common/co_cmdparser.c +build/dedicated_server_common/co_cmdparser.o : src/common/co_cmdparser.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/co_cmdscript.o : src/common/co_cmdscript.c - $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< - -build/dedicated_server_common/cmodel.o : src/common/cmodel.c +build/dedicated_server_common/co_cmdscript.o : src/common/co_cmdscript.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/common.o : src/common/common.c +build/dedicated_server_common/common.o : src/common/common.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/crc.o : src/common/crc.c +build/dedicated_server_common/crc.o : src/common/crc.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/cvar.o : src/common/cvar.c +build/dedicated_server_common/cvar.o : src/common/cvar.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/files.o : src/common/files.c +build/dedicated_server_common/files.o : src/common/files.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/md4.o : src/common/md4.c +build/dedicated_server_common/md4.o : src/common/md4.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/net_chan.o : src/common/net_chan.c +build/dedicated_server_common/net_chan.o : src/common/net_chan.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< -build/dedicated_server_common/pmove.o : src/common/pmove.c +build/dedicated_server_common/pmove.o : src/common/pmove.c $(CC) $(CFLAGS_DEDICATED_SERVER) -o $@ -c $< # ---------- diff --git a/src/common/cm_areaportals.c b/src/common/cm_areaportals.c new file mode 100644 index 00000000..3afddf11 --- /dev/null +++ b/src/common/cm_areaportals.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * This file implements the the area portals. + * + * ======================================================================= + */ + +#include "qcommon.h" +#include "header/cmodel.h" + +extern int numareas; + +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]; + + for (i=0 ; inumareaportals ; i++, p++) + { + if (portalopen[p->portalnum]) + FloodArea_r (&map_areas[p->otherarea], floodnum); + } +} + +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 ; ifloodvalid == floodvalid) + continue; /* already flooded into */ + + floodnum++; + FloodArea_r (area, floodnum); + } + +} + +void CM_SetAreaPortalState (int portalnum, qboolean open) +{ + if (portalnum > 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; +} + +/* + * 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 + */ +int CM_WriteAreaBits (byte *buffer, int area) +{ + int i; + int floodnum; + int bytes; + + bytes = (numareas+7)>>3; + + if (map_noareas->value) + { + /* for debugging, send everything */ + memset (buffer, 255, bytes); + } + + else + { + memset (buffer, 0, bytes); + + floodnum = map_areas[area].floodnum; + + for (i=0 ; i>3] |= 1<<(i&7); + } + } + + return bytes; +} + +/* + * Writes the portal state to a savegame file + */ +void CM_WritePortalState (FILE *f) +{ + fwrite (portalopen, sizeof(portalopen), 1, f); +} + +/* + * Reads the portal state from a savegame file + * and recalculates the area connections + */ +void CM_ReadPortalState (fileHandle_t f) +{ + FS_Read (portalopen, sizeof(portalopen), f); + FloodAreaConnections (); +} + +/* + * Returns true if any leaf under headnode has a cluster that + * is potentially visible + */ +qboolean CM_HeadnodeVisible (int nodenum, byte *visbits) +{ + int leafnum1; + int cluster; + cnode_t *node; + + if (nodenum < 0) + { + leafnum1 = -1-nodenum; + cluster = map_leafs[leafnum1].cluster; + + if (cluster == -1) + return false; + + if (visbits[cluster>>3] & (1<<(cluster&7))) + return true; + + return false; + } + + node = &map_nodes[nodenum]; + + if (CM_HeadnodeVisible(node->children[0], visbits)) + return true; + + return CM_HeadnodeVisible(node->children[1], visbits); +} + diff --git a/src/common/cm_box.c b/src/common/cm_box.c new file mode 100644 index 00000000..9094925f --- /dev/null +++ b/src/common/cm_box.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * This files implements collision boxes for models of all kinds but + * mainly the world model + * + * ======================================================================= + */ + +#include "qcommon.h" +#include "header/cmodel.h" + +extern int numleafs; + +cplane_t *box_planes; +int box_headnode; +cbrush_t *box_brush; +cleaf_t *box_leaf; + +/* + * 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; + cnode_t *c; + cplane_t *p; + cbrushside_t *s; + + box_headnode = numnodes; + box_planes = &map_planes[numplanes]; + + if (numnodes+6 > MAX_MAP_NODES + || numbrushes+1 > MAX_MAP_BRUSHES + || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES + || 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); + c->children[side] = -1 - emptyleaf; + + if (i != 5) + 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; + VectorClear (p->normal); + p->normal[i>>1] = -1; + } +} + +/* + * To keep everything totally uniform, bounding boxes are turned into + * small BSP trees instead of being compared directly. + */ +int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs) +{ + 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]; + + return box_headnode; +} + +int CM_PointLeafnum_r (vec3_t p, int num) +{ + float d; + cnode_t *node; + cplane_t *plane; + + while (num >= 0) + { + node = map_nodes + num; + plane = node->plane; + + if (plane->type < 3) + d = p[plane->type] - plane->dist; + + else + d = DotProduct (plane->normal, p) - plane->dist; + + if (d < 0) + num = node->children[1]; + + else + num = node->children[0]; + } + +#ifndef DEDICATED_ONLY + c_pointcontents++; /* optimize counter */ +#endif + + 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); +} + +/* + * Fills in a list of all the leafs touched + */ +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) + { + if (leaf_count >= leaf_maxcount) + { + return; + } + + leaf_list[leaf_count++] = -1 - nodenum; + return; + } + + node = &map_nodes[nodenum]; + plane = node->plane; + s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane); + + if (s == 1) + nodenum = node->children[0]; + + else if (s == 2) + nodenum = node->children[1]; + + else + { + /* go down both */ + if (leaf_topnode == -1) + leaf_topnode = 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; + leaf_count = 0; + 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); +} + +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; +} + +/* + * Handles offseting and rotation of the end points for moving and + * rotating entities + */ +int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles) +{ + vec3_t p_l; + 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; +} + diff --git a/src/common/cm_boxtracing.c b/src/common/cm_boxtracing.c new file mode 100644 index 00000000..050efe95 --- /dev/null +++ b/src/common/cm_boxtracing.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * This file implements tracing of collision boxes through the world + * model + * + * ======================================================================= + */ + +#include "qcommon.h" +#include "header/cmodel.h" + +extern int box_headnode; + +/* 1/32 epsilon to keep floating point happy */ +#define DIST_EPSILON (0.03125f) + +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 */ + +void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, + trace_t *trace, cbrush_t *brush) +{ + int i, j; + cplane_t *plane, *clipplane; + float dist; + float enterfrac, leavefrac; + vec3_t ofs; + float d1, d2; + qboolean getout, startout; + float f; + cbrushside_t *side, *leadside; + + enterfrac = -1; + leavefrac = 1; + clipplane = NULL; + + if (!brush->numsides) + return; + +#ifndef DEDICATED_ONLY + c_brush_traces++; +#endif + + getout = false; + startout = false; + leadside = NULL; + + for (i=0 ; inumsides ; i++) + { + side = &map_brushsides[brush->firstbrushside+i]; + plane = side->plane; + + if (!trace_ispoint) + { + /* general box case + push the plane out + apropriately for mins/maxs */ + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + + else + ofs[j] = mins[j]; + } + + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + } + + else + { + /* special point case */ + dist = plane->dist; + } + + d1 = DotProduct (p1, plane->normal) - dist; + d2 = DotProduct (p2, plane->normal) - dist; + + if (d2 > 0) + getout = true; /* endpoint is not in solid */ + + if (d1 > 0) + startout = true; + + /* if completely in front of face, no intersection */ + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + /* crosses face */ + if (d1 > d2) + { + /* enter */ + f = (d1-DIST_EPSILON) / (d1-d2); + + if (f > enterfrac) + { + enterfrac = f; + clipplane = plane; + leadside = side; + } + } + + else + { + /* leave */ + f = (d1+DIST_EPSILON) / (d1-d2); + + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) + { + /* original point was inside brush */ + trace->startsolid = true; + + if (!getout) + trace->allsolid = true; + + return; + } + + if (enterfrac < leavefrac) + { + if (enterfrac > -1 && enterfrac < trace->fraction) + { + if (enterfrac < 0) + enterfrac = 0; + + trace->fraction = enterfrac; + trace->plane = *clipplane; + trace->surface = &(leadside->surface->c); + trace->contents = brush->contents; + } + } +} + +void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, + trace_t *trace, cbrush_t *brush) +{ + int i, j; + cplane_t *plane; + float dist; + vec3_t ofs; + float d1; + cbrushside_t *side; + + if (!brush->numsides) + return; + + for (i=0 ; inumsides ; i++) + { + side = &map_brushsides[brush->firstbrushside+i]; + plane = side->plane; + + /* general box case + push the plane out + apropriately for mins/maxs */ + for (j=0 ; j<3 ; j++) + { + if (plane->normal[j] < 0) + ofs[j] = maxs[j]; + + else + ofs[j] = mins[j]; + } + + dist = DotProduct (ofs, plane->normal); + dist = plane->dist - dist; + + d1 = DotProduct (p1, plane->normal) - dist; + + /* if completely in front of face, no intersection */ + if (d1 > 0) + return; + + } + + /* inside this brush */ + trace->startsolid = trace->allsolid = true; + trace->fraction = 0; + trace->contents = brush->contents; +} + +void CM_TraceToLeaf (int leafnum) +{ + int k; + int brushnum; + cleaf_t *leaf; + cbrush_t *b; + + leaf = &map_leafs[leafnum]; + + if ( !(leaf->contents & trace_contents)) + return; + + /* trace line against all brushes in the leaf */ + for (k=0 ; knumleafbrushes ; k++) + { + brushnum = map_leafbrushes[leaf->firstleafbrush+k]; + b = &map_brushes[brushnum]; + + if (b->checkcount == checkcount) + continue; /* already checked this brush in another leaf */ + + b->checkcount = checkcount; + + if ( !(b->contents & trace_contents)) + continue; + + CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b); + + if (!trace_trace.fraction) + return; + } + +} + +void CM_TestInLeaf (int leafnum) +{ + int k; + int brushnum; + cleaf_t *leaf; + cbrush_t *b; + + leaf = &map_leafs[leafnum]; + + if ( !(leaf->contents & trace_contents)) + return; + + /* trace line against all brushes in the leaf */ + for (k=0 ; knumleafbrushes ; k++) + { + brushnum = map_leafbrushes[leaf->firstleafbrush+k]; + b = &map_brushes[brushnum]; + + if (b->checkcount == checkcount) + continue; /* already checked this brush in another leaf */ + + b->checkcount = checkcount; + + if ( !(b->contents & trace_contents)) + continue; + + CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b); + + if (!trace_trace.fraction) + return; + } + +} + +void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2) +{ + cnode_t *node; + cplane_t *plane; + float t1, t2, offset; + float frac, frac2; + float idist; + int i; + 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; + t2 = p2[plane->type] - plane->dist; + offset = trace_extents[plane->type]; + } + + else + { + t1 = DotProduct (plane->normal, p1) - plane->dist; + t2 = DotProduct (plane->normal, p2) - plane->dist; + + if (trace_ispoint) + offset = 0; + + else + offset = (float)fabs(trace_extents[0]*plane->normal[0]) + + (float)fabs(trace_extents[1]*plane->normal[1]) + + (float)fabs(trace_extents[2]*plane->normal[2]); + } + + /* see which sides we need to consider */ + if (t1 >= offset && t2 >= offset) + { + CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2); + return; + } + + if (t1 < -offset && t2 < -offset) + { + CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); + return; + } + + /* put the crosspoint DIST_EPSILON pixels on the near side */ + if (t1 < t2) + { + idist = 1.0f/(t1-t2); + side = 1; + frac2 = (t1 + offset + DIST_EPSILON)*idist; + frac = (t1 - offset + DIST_EPSILON)*idist; + } + + else if (t1 > t2) + { + idist = 1.0/(t1-t2); + side = 0; + frac2 = (t1 - offset - DIST_EPSILON)*idist; + frac = (t1 + offset + DIST_EPSILON)*idist; + } + + else + { + side = 0; + frac = 1; + frac2 = 0; + } + + /* move up to the node */ + if (frac < 0) + frac = 0; + + if (frac > 1) + frac = 1; + + 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; + + if (frac2 > 1) + frac2 = 1; + + 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); +} + +trace_t CM_BoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask) +{ + int i; + + checkcount++; /* for multi-check avoidance */ + +#ifndef DEDICATED_ONLY + c_traces++; /* for statistics, may be zeroed */ +#endif + + /* fill in a default trace */ + memset (&trace_trace, 0, sizeof(trace_trace)); + trace_trace.fraction = 1; + trace_trace.surface = &(nullsurface.c); + + if (!numnodes) /* map not loaded */ + return trace_trace; + + trace_contents = brushmask; + VectorCopy (start, trace_start); + VectorCopy (end, trace_end); + VectorCopy (mins, trace_mins); + VectorCopy (maxs, trace_maxs); + + /* check for position test special case */ + if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) + { + int leafs[1024]; + int i, numleafs; + vec3_t c1, c2; + int topnode; + + VectorAdd (start, mins, c1); + VectorAdd (start, maxs, c2); + + for (i=0 ; i<3 ; i++) + { + c1[i] -= 1; + c2[i] += 1; + } + + numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode); + + for (i=0 ; i maxs[0] ? -mins[0] : maxs[0]; + trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; + trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; + } + + /* general sweeping through world */ + CM_RecursiveHullCheck (headnode, 0, 1, start, end); + + if (trace_trace.fraction == 1) + { + VectorCopy (end, trace_trace.endpos); + } + + else + { + for (i=0 ; i<3 ; i++) + trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); + } + + return trace_trace; +} + +/* + * Handles offseting and rotation of the end points for moving and + * rotating entities + */ +trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, + vec3_t origin, vec3_t angles) +{ + trace_t trace; + vec3_t start_l, end_l; + vec3_t a; + 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) + { + 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; +} + diff --git a/src/common/cm_bsp.c b/src/common/cm_bsp.c new file mode 100644 index 00000000..c27b4f68 --- /dev/null +++ b/src/common/cm_bsp.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * This file implements loading and parsing of BSP files and trees. + * + * ======================================================================= + */ + +#include "qcommon.h" +#include "header/cmodel.h" + +extern dvis_t *map_vis; + +int numleafs = 1; /* allow leaf funcs to be called without a map */ +int numclusters = 1; +int numareas = 1; + +byte *cmod_base; + +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; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + + out->headnode = LittleLong (in->headnode); + } +} + +void CMod_LoadSurfaces (lump_t *l) +{ + texinfo_t *in; + 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"); + + count = l->filelen / sizeof(*in); + + if (count < 1) + 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 ; ic.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); + } +} + +void CMod_LoadNodes (lump_t *l) +{ + dnode_t *in; + int child; + cnode_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 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); + + for (j=0 ; j<2 ; j++) + { + child = LittleLong (in->children[j]); + out->children[j] = child; + } + } + +} + +void CMod_LoadBrushes (lump_t *l) +{ + dbrush_t *in; + cbrush_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"); + + 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); + } + +} + +void CMod_LoadLeafs (lump_t *l) +{ + int i; + cleaf_t *out; + dleaf_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 < 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); + out->cluster = LittleShort (in->cluster); + 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; + emptyleaf = -1; + + for (i=1 ; ifileofs); + + 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] = LittleFloat (in->normal[j]); + + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + +void CMod_LoadLeafBrushes (lump_t *l) +{ + int i; + unsigned short *out; + unsigned short *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 < 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); + out->plane = &map_planes[num]; + j = LittleShort (in->texinfo); + + if (j >= numtexinfo) + Com_Error (ERR_DROP, "Bad brushside texinfo"); + + out->surface = &map_surfaces[j]; + } +} + +void CMod_LoadAreas (lump_t *l) +{ + int i; + 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); + out->firstareaportal = LittleLong (in->firstareaportal); + out->floodvalid = 0; + out->floodnum = 0; + } +} + +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; + + memcpy (out, in, sizeof(dareaportal_t)*count); +} + +void CMod_LoadVisibility (lump_t *l) +{ + 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); +} + +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); +} + +/* + * Loads in the map and all submodels + */ +cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum) +{ + unsigned *buf; + int i; + 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; + + if (!clientload) + { + memset (portalopen, 0, sizeof(portalopen)); + FloodAreaConnections (); + } + + return &map_cmodels[0]; /* still have the right version */ + } + + /* free old stuff */ + numplanes = 0; + numnodes = 0; + numleafs = 0; + numcmodels = 0; + numvisibility = 0; + numentitychars = 0; + map_entitystring[0] = 0; + map_name[0] = 0; + + if (!name || !name[0]) + { + numleafs = 1; + numclusters = 1; + numareas = 1; + *checksum = 0; + return &map_cmodels[0]; /* cinematic servers won't have anything at all */ + } + + length = FS_LoadFile (name, (void **)&buf); + + if (!buf) + Com_Error (ERR_DROP, "Couldn't load %s", name); + + 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; +} + diff --git a/src/common/cm_vis.c b/src/common/cm_vis.c new file mode 100644 index 00000000..4afb77bd --- /dev/null +++ b/src/common/cm_vis.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * This file implements loading an parsing of the vis of a map or model + * + * ======================================================================= + */ + +#include "qcommon.h" +#include "header/cmodel.h" + +extern int numclusters; + +dvis_t *map_vis = (dvis_t *)map_visibility; + +void CM_DecompressVis (byte *in, byte *out) +{ + int c; + byte *out_p; + int row; + + row = (numclusters+7)>>3; + out_p = out; + + if (!in || !numvisibility) + { + /* no vis info, so make all visible */ + while (row) + { + *out_p++ = 0xff; + row--; + } + + return; + } + + do + { + if (*in) + { + *out_p++ = *in++; + continue; + } + + c = in[1]; + in += 2; + + if ((out_p - out) + c > row) + { + c = row - (out_p - out); + Com_DPrintf ("warning: Vis decompression overrun\n"); + } + + while (c) + { + *out_p++ = 0; + c--; + } + } + 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) + memset (pvsrow, 0, (numclusters+7)>>3); + + else + CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow); + + return pvsrow; +} + +byte *CM_ClusterPHS (int cluster) +{ + if (cluster == -1) + memset (phsrow, 0, (numclusters+7)>>3); + + else + CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow); + + return phsrow; +} + diff --git a/src/common/cmodel.c b/src/common/cmodel.c deleted file mode 100644 index 946343c7..00000000 --- a/src/common/cmodel.c +++ /dev/null @@ -1,1645 +0,0 @@ -/* -Copyright (C) 1997-2001 Id Software, Inc. - -This program 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 2 -of the License, or (at your option) any later version. - -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// 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; - mapsurface_t *surface; -} cbrushside_t; - -typedef struct -{ - int contents; - int cluster; - int area; - unsigned short firstleafbrush; - unsigned short numleafbrushes; -} cleaf_t; - -typedef struct -{ - int contents; - int numsides; - int firstbrushside; - int checkcount; /* to avoid repeated testings */ -} cbrush_t; - -typedef struct -{ - int numareaportals; - int firstareaportal; - 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; -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; - -mapsurface_t nullsurface; - -int floodvalid; - -qboolean portalopen[MAX_MAP_AREAPORTALS]; - -cvar_t *map_noareas; - -void CM_InitBoxHull (void); -void FloodAreaConnections (void); - -#ifndef DEDICATED_ONLY -int c_pointcontents; -int c_traces, c_brush_traces; -#endif - -/* MAP LOADING */ - -byte *cmod_base; - -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; - out->maxs[j] = LittleFloat (in->maxs[j]) + 1; - out->origin[j] = LittleFloat (in->origin[j]); - } - - out->headnode = LittleLong (in->headnode); - } -} - -void CMod_LoadSurfaces (lump_t *l) -{ - texinfo_t *in; - 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"); - - count = l->filelen / sizeof(*in); - - if (count < 1) - 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 ; ic.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); - } -} - -void CMod_LoadNodes (lump_t *l) -{ - dnode_t *in; - int child; - cnode_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 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); - - for (j=0 ; j<2 ; j++) - { - child = LittleLong (in->children[j]); - out->children[j] = child; - } - } - -} - -void CMod_LoadBrushes (lump_t *l) -{ - dbrush_t *in; - cbrush_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"); - - 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); - } - -} - -void CMod_LoadLeafs (lump_t *l) -{ - int i; - cleaf_t *out; - dleaf_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 < 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); - out->cluster = LittleShort (in->cluster); - 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; - emptyleaf = -1; - - for (i=1 ; ifileofs); - - 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] = LittleFloat (in->normal[j]); - - if (out->normal[j] < 0) - bits |= 1<dist = LittleFloat (in->dist); - out->type = LittleLong (in->type); - out->signbits = bits; - } -} - -void CMod_LoadLeafBrushes (lump_t *l) -{ - int i; - unsigned short *out; - unsigned short *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 < 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); - out->plane = &map_planes[num]; - j = LittleShort (in->texinfo); - - if (j >= numtexinfo) - Com_Error (ERR_DROP, "Bad brushside texinfo"); - - out->surface = &map_surfaces[j]; - } -} - -void CMod_LoadAreas (lump_t *l) -{ - int i; - 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); - out->firstareaportal = LittleLong (in->firstareaportal); - out->floodvalid = 0; - out->floodnum = 0; - } -} - -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; - - memcpy (out, in, sizeof(dareaportal_t)*count); -} - -void CMod_LoadVisibility (lump_t *l) -{ - 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); -} - -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); -} - -/* - * Loads in the map and all submodels - */ -cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum) -{ - unsigned *buf; - int i; - 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; - - if (!clientload) - { - memset (portalopen, 0, sizeof(portalopen)); - FloodAreaConnections (); - } - - return &map_cmodels[0]; /* still have the right version */ - } - - /* free old stuff */ - numplanes = 0; - numnodes = 0; - numleafs = 0; - numcmodels = 0; - numvisibility = 0; - numentitychars = 0; - map_entitystring[0] = 0; - map_name[0] = 0; - - if (!name || !name[0]) - { - numleafs = 1; - numclusters = 1; - numareas = 1; - *checksum = 0; - return &map_cmodels[0]; /* cinematic servers won't have anything at all */ - } - - length = FS_LoadFile (name, (void **)&buf); - - if (!buf) - Com_Error (ERR_DROP, "Couldn't load %s", name); - - 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; - -/* - * 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; - cnode_t *c; - cplane_t *p; - cbrushside_t *s; - - box_headnode = numnodes; - box_planes = &map_planes[numplanes]; - - if (numnodes+6 > MAX_MAP_NODES - || numbrushes+1 > MAX_MAP_BRUSHES - || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES - || 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); - c->children[side] = -1 - emptyleaf; - - if (i != 5) - 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; - VectorClear (p->normal); - p->normal[i>>1] = -1; - } -} - -/* - * To keep everything totally uniform, bounding boxes are turned into - * small BSP trees instead of being compared directly. - */ -int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs) -{ - 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]; - - return box_headnode; -} - -int CM_PointLeafnum_r (vec3_t p, int num) -{ - float d; - cnode_t *node; - cplane_t *plane; - - while (num >= 0) - { - node = map_nodes + num; - plane = node->plane; - - if (plane->type < 3) - d = p[plane->type] - plane->dist; - - else - d = DotProduct (plane->normal, p) - plane->dist; - - if (d < 0) - num = node->children[1]; - - else - num = node->children[0]; - } - -#ifndef DEDICATED_ONLY - c_pointcontents++; /* optimize counter */ -#endif - - 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); -} - -/* - * Fills in a list of all the leafs touched - */ -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) - { - if (leaf_count >= leaf_maxcount) - { - return; - } - - leaf_list[leaf_count++] = -1 - nodenum; - return; - } - - node = &map_nodes[nodenum]; - plane = node->plane; - s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane); - - if (s == 1) - nodenum = node->children[0]; - - else if (s == 2) - nodenum = node->children[1]; - - else - { - /* go down both */ - if (leaf_topnode == -1) - leaf_topnode = 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; - leaf_count = 0; - 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); -} - -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; -} - -/* - * Handles offseting and rotation of the end points for moving and - * rotating entities - */ -int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles) -{ - vec3_t p_l; - 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.03125f) - -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 */ - -void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, - trace_t *trace, cbrush_t *brush) -{ - int i, j; - cplane_t *plane, *clipplane; - float dist; - float enterfrac, leavefrac; - vec3_t ofs; - float d1, d2; - qboolean getout, startout; - float f; - cbrushside_t *side, *leadside; - - enterfrac = -1; - leavefrac = 1; - clipplane = NULL; - - if (!brush->numsides) - return; - -#ifndef DEDICATED_ONLY - c_brush_traces++; -#endif - - getout = false; - startout = false; - leadside = NULL; - - for (i=0 ; inumsides ; i++) - { - side = &map_brushsides[brush->firstbrushside+i]; - plane = side->plane; - - if (!trace_ispoint) - { - /* general box case - push the plane out - apropriately for mins/maxs */ - for (j=0 ; j<3 ; j++) - { - if (plane->normal[j] < 0) - ofs[j] = maxs[j]; - - else - ofs[j] = mins[j]; - } - - dist = DotProduct (ofs, plane->normal); - dist = plane->dist - dist; - } - - else - { - /* special point case */ - dist = plane->dist; - } - - d1 = DotProduct (p1, plane->normal) - dist; - d2 = DotProduct (p2, plane->normal) - dist; - - if (d2 > 0) - getout = true; /* endpoint is not in solid */ - - if (d1 > 0) - startout = true; - - /* if completely in front of face, no intersection */ - if (d1 > 0 && d2 >= d1) - return; - - if (d1 <= 0 && d2 <= 0) - continue; - - /* crosses face */ - if (d1 > d2) - { - /* enter */ - f = (d1-DIST_EPSILON) / (d1-d2); - - if (f > enterfrac) - { - enterfrac = f; - clipplane = plane; - leadside = side; - } - } - - else - { - /* leave */ - f = (d1+DIST_EPSILON) / (d1-d2); - - if (f < leavefrac) - leavefrac = f; - } - } - - if (!startout) - { - /* original point was inside brush */ - trace->startsolid = true; - - if (!getout) - trace->allsolid = true; - - return; - } - - if (enterfrac < leavefrac) - { - if (enterfrac > -1 && enterfrac < trace->fraction) - { - if (enterfrac < 0) - enterfrac = 0; - - trace->fraction = enterfrac; - trace->plane = *clipplane; - trace->surface = &(leadside->surface->c); - trace->contents = brush->contents; - } - } -} - -void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1, - trace_t *trace, cbrush_t *brush) -{ - int i, j; - cplane_t *plane; - float dist; - vec3_t ofs; - float d1; - cbrushside_t *side; - - if (!brush->numsides) - return; - - for (i=0 ; inumsides ; i++) - { - side = &map_brushsides[brush->firstbrushside+i]; - plane = side->plane; - - /* general box case - push the plane out - apropriately for mins/maxs */ - for (j=0 ; j<3 ; j++) - { - if (plane->normal[j] < 0) - ofs[j] = maxs[j]; - - else - ofs[j] = mins[j]; - } - - dist = DotProduct (ofs, plane->normal); - dist = plane->dist - dist; - - d1 = DotProduct (p1, plane->normal) - dist; - - /* if completely in front of face, no intersection */ - if (d1 > 0) - return; - - } - - /* inside this brush */ - trace->startsolid = trace->allsolid = true; - trace->fraction = 0; - trace->contents = brush->contents; -} - -void CM_TraceToLeaf (int leafnum) -{ - int k; - int brushnum; - cleaf_t *leaf; - cbrush_t *b; - - leaf = &map_leafs[leafnum]; - - if ( !(leaf->contents & trace_contents)) - return; - - /* trace line against all brushes in the leaf */ - for (k=0 ; knumleafbrushes ; k++) - { - brushnum = map_leafbrushes[leaf->firstleafbrush+k]; - b = &map_brushes[brushnum]; - - if (b->checkcount == checkcount) - continue; /* already checked this brush in another leaf */ - - b->checkcount = checkcount; - - if ( !(b->contents & trace_contents)) - continue; - - CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b); - - if (!trace_trace.fraction) - return; - } - -} - -void CM_TestInLeaf (int leafnum) -{ - int k; - int brushnum; - cleaf_t *leaf; - cbrush_t *b; - - leaf = &map_leafs[leafnum]; - - if ( !(leaf->contents & trace_contents)) - return; - - /* trace line against all brushes in the leaf */ - for (k=0 ; knumleafbrushes ; k++) - { - brushnum = map_leafbrushes[leaf->firstleafbrush+k]; - b = &map_brushes[brushnum]; - - if (b->checkcount == checkcount) - continue; /* already checked this brush in another leaf */ - - b->checkcount = checkcount; - - if ( !(b->contents & trace_contents)) - continue; - - CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b); - - if (!trace_trace.fraction) - return; - } - -} - -void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2) -{ - cnode_t *node; - cplane_t *plane; - float t1, t2, offset; - float frac, frac2; - float idist; - int i; - 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; - t2 = p2[plane->type] - plane->dist; - offset = trace_extents[plane->type]; - } - - else - { - t1 = DotProduct (plane->normal, p1) - plane->dist; - t2 = DotProduct (plane->normal, p2) - plane->dist; - - if (trace_ispoint) - offset = 0; - - else - offset = (float)fabs(trace_extents[0]*plane->normal[0]) + - (float)fabs(trace_extents[1]*plane->normal[1]) + - (float)fabs(trace_extents[2]*plane->normal[2]); - } - - /* see which sides we need to consider */ - if (t1 >= offset && t2 >= offset) - { - CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2); - return; - } - - if (t1 < -offset && t2 < -offset) - { - CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2); - return; - } - - /* put the crosspoint DIST_EPSILON pixels on the near side */ - if (t1 < t2) - { - idist = 1.0f/(t1-t2); - side = 1; - frac2 = (t1 + offset + DIST_EPSILON)*idist; - frac = (t1 - offset + DIST_EPSILON)*idist; - } - - else if (t1 > t2) - { - idist = 1.0/(t1-t2); - side = 0; - frac2 = (t1 - offset - DIST_EPSILON)*idist; - frac = (t1 + offset + DIST_EPSILON)*idist; - } - - else - { - side = 0; - frac = 1; - frac2 = 0; - } - - /* move up to the node */ - if (frac < 0) - frac = 0; - - if (frac > 1) - frac = 1; - - 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; - - if (frac2 > 1) - frac2 = 1; - - 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); -} - -/* ====================================================================== */ - -trace_t CM_BoxTrace (vec3_t start, vec3_t end, - vec3_t mins, vec3_t maxs, - int headnode, int brushmask) -{ - int i; - - checkcount++; /* for multi-check avoidance */ - -#ifndef DEDICATED_ONLY - c_traces++; /* for statistics, may be zeroed */ -#endif - - /* fill in a default trace */ - memset (&trace_trace, 0, sizeof(trace_trace)); - trace_trace.fraction = 1; - trace_trace.surface = &(nullsurface.c); - - if (!numnodes) /* map not loaded */ - return trace_trace; - - trace_contents = brushmask; - VectorCopy (start, trace_start); - VectorCopy (end, trace_end); - VectorCopy (mins, trace_mins); - VectorCopy (maxs, trace_maxs); - - /* check for position test special case */ - if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) - { - int leafs[1024]; - int i, numleafs; - vec3_t c1, c2; - int topnode; - - VectorAdd (start, mins, c1); - VectorAdd (start, maxs, c2); - - for (i=0 ; i<3 ; i++) - { - c1[i] -= 1; - c2[i] += 1; - } - - numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode); - - for (i=0 ; i maxs[0] ? -mins[0] : maxs[0]; - trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; - trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; - } - - /* general sweeping through world */ - CM_RecursiveHullCheck (headnode, 0, 1, start, end); - - if (trace_trace.fraction == 1) - { - VectorCopy (end, trace_trace.endpos); - } - - else - { - for (i=0 ; i<3 ; i++) - trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); - } - - return trace_trace; -} - -/* - * Handles offseting and rotation of the end points for moving and - * rotating entities - */ -trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, - vec3_t mins, vec3_t maxs, - int headnode, int brushmask, - vec3_t origin, vec3_t angles) -{ - trace_t trace; - vec3_t start_l, end_l; - vec3_t a; - 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) - { - 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; -} - -/* PVS / PHS */ - -void CM_DecompressVis (byte *in, byte *out) -{ - int c; - byte *out_p; - int row; - - row = (numclusters+7)>>3; - out_p = out; - - if (!in || !numvisibility) - { - /* no vis info, so make all visible */ - while (row) - { - *out_p++ = 0xff; - row--; - } - - return; - } - - do - { - if (*in) - { - *out_p++ = *in++; - continue; - } - - c = in[1]; - in += 2; - - if ((out_p - out) + c > row) - { - c = row - (out_p - out); - Com_DPrintf ("warning: Vis decompression overrun\n"); - } - - while (c) - { - *out_p++ = 0; - c--; - } - } - 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) - memset (pvsrow, 0, (numclusters+7)>>3); - - else - CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow); - - return pvsrow; -} - -byte *CM_ClusterPHS (int cluster) -{ - if (cluster == -1) - memset (phsrow, 0, (numclusters+7)>>3); - - else - 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]; - - for (i=0 ; inumareaportals ; i++, p++) - { - if (portalopen[p->portalnum]) - FloodArea_r (&map_areas[p->otherarea], floodnum); - } -} - -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 ; ifloodvalid == floodvalid) - continue; /* already flooded into */ - - floodnum++; - FloodArea_r (area, floodnum); - } - -} - -void CM_SetAreaPortalState (int portalnum, qboolean open) -{ - if (portalnum > 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; -} - -/* - * 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 - */ -int CM_WriteAreaBits (byte *buffer, int area) -{ - int i; - int floodnum; - int bytes; - - bytes = (numareas+7)>>3; - - if (map_noareas->value) - { - /* for debugging, send everything */ - memset (buffer, 255, bytes); - } - - else - { - memset (buffer, 0, bytes); - - floodnum = map_areas[area].floodnum; - - for (i=0 ; i>3] |= 1<<(i&7); - } - } - - return bytes; -} - -/* - * Writes the portal state to a savegame file - */ -void CM_WritePortalState (FILE *f) -{ - fwrite (portalopen, sizeof(portalopen), 1, f); -} - -/* - * Reads the portal state from a savegame file - * and recalculates the area connections - */ -void CM_ReadPortalState (fileHandle_t f) -{ - FS_Read (portalopen, sizeof(portalopen), f); - FloodAreaConnections (); -} - -/* - * Returns true if any leaf under headnode has a cluster that - * is potentially visible - */ -qboolean CM_HeadnodeVisible (int nodenum, byte *visbits) -{ - int leafnum; - int cluster; - cnode_t *node; - - if (nodenum < 0) - { - leafnum = -1-nodenum; - cluster = map_leafs[leafnum].cluster; - - if (cluster == -1) - return false; - - if (visbits[cluster>>3] & (1<<(cluster&7))) - return true; - - return false; - } - - node = &map_nodes[nodenum]; - - if (CM_HeadnodeVisible(node->children[0], visbits)) - return true; - - return CM_HeadnodeVisible(node->children[1], visbits); -} diff --git a/src/common/header/cmodel.h b/src/common/header/cmodel.h new file mode 100644 index 00000000..772fd70f --- /dev/null +++ b/src/common/header/cmodel.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program 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 2 of the License, or (at + * your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * The header file for the common model stuff. + * + * ======================================================================= + */ + +#ifndef CO_CMODEL_H +#define CO_CMODEL_H + +typedef struct +{ + cplane_t *plane; + int children[2]; /* negative numbers are leafs */ +} cnode_t; + +typedef struct +{ + cplane_t *plane; + mapsurface_t *surface; +} cbrushside_t; + +typedef struct +{ + int contents; + int cluster; + int area; + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} cleaf_t; + +typedef struct +{ + int contents; + int numsides; + int firstbrushside; + int checkcount; /* to avoid repeated testings */ +} cbrush_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; + 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; +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 */ + +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]; + +int numentitychars; +char map_entitystring[MAX_MAP_ENTSTRING]; + +carea_t map_areas[MAX_MAP_AREAS]; + +int numareaportals; +dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; + +mapsurface_t nullsurface; + +int floodvalid; + +qboolean portalopen[MAX_MAP_AREAPORTALS]; + +cvar_t *map_noareas; + +void CM_InitBoxHull (void); +void FloodAreaConnections (void); + +#ifndef DEDICATED_ONLY +int c_pointcontents; +int c_traces, c_brush_traces; +#endif + +int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode); + +#endif + diff --git a/src/common/qcommon.h b/src/common/qcommon.h index 9be508e3..a8808857 100644 --- a/src/common/qcommon.h +++ b/src/common/qcommon.h @@ -20,6 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // qcommon.h -- definitions common between client and server, but not game.dll +#ifndef CM_QCOMMON_H +#define CM_QCOMMON_H + #include "../game/baseq2/q_shared.h" #define VERSION 2.11 @@ -836,4 +839,4 @@ void SV_Shutdown (char *finalmsg, qboolean reconnect); void SV_Frame (int msec); - +#endif