396 lines
8.4 KiB
C
396 lines
8.4 KiB
C
|
#include "quakedef.h"
|
||
|
|
||
|
/*
|
||
|
|
||
|
============================================================================
|
||
|
|
||
|
Physics functions (common)
|
||
|
*/
|
||
|
|
||
|
#if !id386
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
SV_HullPointContents
|
||
|
|
||
|
==================
|
||
|
*/
|
||
|
static int Q1_HullPointContents (hull_t *hull, int num, vec3_t p)
|
||
|
{
|
||
|
float d;
|
||
|
dclipnode_t *node;
|
||
|
mplane_t *plane;
|
||
|
|
||
|
while (num >= 0)
|
||
|
{
|
||
|
if (num < hull->firstclipnode || num > hull->lastclipnode)
|
||
|
SV_Error ("SV_HullPointContents: bad node number");
|
||
|
|
||
|
node = hull->clipnodes + num;
|
||
|
plane = hull->planes + node->planenum;
|
||
|
|
||
|
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];
|
||
|
}
|
||
|
|
||
|
return num;
|
||
|
}
|
||
|
#else
|
||
|
int VARGS Q1_HullPointContents (hull_t *hull, int num, vec3_t p);
|
||
|
#endif // !id386
|
||
|
|
||
|
|
||
|
|
||
|
#define DIST_EPSILON (0.03125)
|
||
|
qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||
|
{
|
||
|
dclipnode_t *node;
|
||
|
mplane_t *plane;
|
||
|
float t1, t2;
|
||
|
float frac;
|
||
|
int i;
|
||
|
vec3_t mid;
|
||
|
int side;
|
||
|
float midf;
|
||
|
|
||
|
// check for empty
|
||
|
if (num < 0)
|
||
|
{
|
||
|
if (num != Q1CONTENTS_SOLID)
|
||
|
{
|
||
|
trace->allsolid = false;
|
||
|
if (num == Q1CONTENTS_EMPTY)
|
||
|
trace->inopen = true;
|
||
|
else
|
||
|
trace->inwater = true;
|
||
|
}
|
||
|
else
|
||
|
trace->startsolid = true;
|
||
|
return true; // empty
|
||
|
}
|
||
|
|
||
|
if (num < hull->firstclipnode || num > hull->lastclipnode)
|
||
|
SV_Error ("Q1BSP_RecursiveHullCheck: bad node number");
|
||
|
|
||
|
//
|
||
|
// find the point distances
|
||
|
//
|
||
|
node = hull->clipnodes + num;
|
||
|
plane = hull->planes + node->planenum;
|
||
|
|
||
|
if (plane->type < 3)
|
||
|
{
|
||
|
t1 = p1[plane->type] - plane->dist;
|
||
|
t2 = p2[plane->type] - plane->dist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
t1 = DotProduct (plane->normal, p1) - plane->dist;
|
||
|
t2 = DotProduct (plane->normal, p2) - plane->dist;
|
||
|
}
|
||
|
|
||
|
#if 1
|
||
|
if (t1 >= 0 && t2 >= 0)
|
||
|
return Q1BSP_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
||
|
if (t1 < 0 && t2 < 0)
|
||
|
return Q1BSP_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
||
|
#else
|
||
|
if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
|
||
|
return Q1BSP_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
|
||
|
if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
|
||
|
return Q1BSP_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
|
||
|
#endif
|
||
|
|
||
|
// put the crosspoint DIST_EPSILON pixels on the near side
|
||
|
if (t1 < 0)
|
||
|
frac = (t1 + DIST_EPSILON)/(t1-t2);
|
||
|
else
|
||
|
frac = (t1 - DIST_EPSILON)/(t1-t2);
|
||
|
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]);
|
||
|
|
||
|
side = (t1 < 0);
|
||
|
|
||
|
// move up to the node
|
||
|
if (!Q1BSP_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
|
||
|
return false;
|
||
|
|
||
|
#ifdef PARANOID
|
||
|
if (Q1BSP_RecursiveHullCheck (sv_hullmodel, mid, node->children[side])
|
||
|
== Q1CONTENTS_SOLID)
|
||
|
{
|
||
|
Con_Printf ("mid PointInHullSolid\n");
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (Q1_HullPointContents (hull, node->children[side^1], mid)
|
||
|
!= Q1CONTENTS_SOLID)
|
||
|
// go past the node
|
||
|
return Q1BSP_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
|
||
|
|
||
|
if (trace->allsolid)
|
||
|
return false; // never got out of the solid area
|
||
|
|
||
|
//==================
|
||
|
// the other side of the node is solid, this is the impact point
|
||
|
//==================
|
||
|
if (!side)
|
||
|
{
|
||
|
VectorCopy (plane->normal, trace->plane.normal);
|
||
|
trace->plane.dist = plane->dist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
|
||
|
trace->plane.dist = -plane->dist;
|
||
|
}
|
||
|
|
||
|
while (Q1_HullPointContents (hull, hull->firstclipnode, mid)
|
||
|
== Q1CONTENTS_SOLID)
|
||
|
{ // shouldn't really happen, but does occasionally
|
||
|
frac -= 0.1;
|
||
|
if (frac < 0)
|
||
|
{
|
||
|
trace->fraction = midf;
|
||
|
VectorCopy (mid, trace->endpos);
|
||
|
Con_DPrintf ("backup past 0\n");
|
||
|
return false;
|
||
|
}
|
||
|
midf = p1f + (p2f - p1f)*frac;
|
||
|
for (i=0 ; i<3 ; i++)
|
||
|
mid[i] = p1[i] + frac*(p2[i] - p1[i]);
|
||
|
}
|
||
|
|
||
|
trace->fraction = midf;
|
||
|
VectorCopy (mid, trace->endpos);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int Q1BSP_HullPointContents(hull_t *hull, vec3_t p)
|
||
|
{
|
||
|
switch(Q1_HullPointContents(hull, hull->firstclipnode, p))
|
||
|
{
|
||
|
case Q1CONTENTS_EMPTY:
|
||
|
return FTECONTENTS_EMPTY;
|
||
|
case Q1CONTENTS_SOLID:
|
||
|
return FTECONTENTS_SOLID;
|
||
|
case Q1CONTENTS_WATER:
|
||
|
return FTECONTENTS_WATER;
|
||
|
case Q1CONTENTS_SLIME:
|
||
|
return FTECONTENTS_SLIME;
|
||
|
case Q1CONTENTS_LAVA:
|
||
|
return FTECONTENTS_LAVA;
|
||
|
case Q1CONTENTS_SKY:
|
||
|
return FTECONTENTS_SKY;
|
||
|
default:
|
||
|
Sys_Error("Q1_PointContents: Unknown contents type");
|
||
|
return FTECONTENTS_SOLID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Q1BSP_SetHullFuncs(hull_t *hull)
|
||
|
{
|
||
|
hull->funcs.RecursiveHullCheck = Q1BSP_RecursiveHullCheck;
|
||
|
hull->funcs.HullPointContents = Q1BSP_HullPointContents;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Physics functions (common)
|
||
|
|
||
|
============================================================================
|
||
|
|
||
|
Rendering functions (Client only)
|
||
|
*/
|
||
|
#ifndef SERVERONLY
|
||
|
|
||
|
extern int r_dlightframecount;
|
||
|
|
||
|
//goes through the nodes marking the surfaces near the dynamic light as lit.
|
||
|
void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node)
|
||
|
{
|
||
|
mplane_t *splitplane;
|
||
|
float dist;
|
||
|
msurface_t *surf;
|
||
|
int i;
|
||
|
|
||
|
if (node->contents < 0)
|
||
|
return;
|
||
|
|
||
|
splitplane = node->plane;
|
||
|
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
|
||
|
|
||
|
if (dist > light->radius)
|
||
|
{
|
||
|
Q1BSP_MarkLights (light, bit, node->children[0]);
|
||
|
return;
|
||
|
}
|
||
|
if (dist < -light->radius)
|
||
|
{
|
||
|
Q1BSP_MarkLights (light, bit, node->children[1]);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// mark the polygons
|
||
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
||
|
for (i=0 ; i<node->numsurfaces ; i++, surf++)
|
||
|
{
|
||
|
if (surf->dlightframe != r_dlightframecount)
|
||
|
{
|
||
|
surf->dlightbits = 0;
|
||
|
surf->dlightframe = r_dlightframecount;
|
||
|
}
|
||
|
surf->dlightbits |= bit;
|
||
|
}
|
||
|
|
||
|
Q1BSP_MarkLights (light, bit, node->children[0]);
|
||
|
Q1BSP_MarkLights (light, bit, node->children[1]);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
/*
|
||
|
Rendering functions (Client only)
|
||
|
|
||
|
==============================================================================
|
||
|
|
||
|
Server only functions
|
||
|
*/
|
||
|
|
||
|
|
||
|
extern int fatbytes;
|
||
|
extern qbyte fatpvs[(MAX_MAP_LEAFS+1)/4];
|
||
|
|
||
|
//does the recursive work of Q1BSP_FatPVS
|
||
|
void SV_Q1BSP_AddToFatPVS (vec3_t org, mnode_t *node)
|
||
|
{
|
||
|
int i;
|
||
|
qbyte *pvs;
|
||
|
mplane_t *plane;
|
||
|
float d;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
// if this is a leaf, accumulate the pvs bits
|
||
|
if (node->contents < 0)
|
||
|
{
|
||
|
if (node->contents != Q1CONTENTS_SOLID)
|
||
|
{
|
||
|
pvs = Mod_Q1LeafPVS ( (mleaf_t *)node, sv.worldmodel, NULL);
|
||
|
for (i=0 ; i<fatbytes ; i++)
|
||
|
fatpvs[i] |= pvs[i];
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
plane = node->plane;
|
||
|
d = DotProduct (org, plane->normal) - plane->dist;
|
||
|
if (d > 8)
|
||
|
node = node->children[0];
|
||
|
else if (d < -8)
|
||
|
node = node->children[1];
|
||
|
else
|
||
|
{ // go down both
|
||
|
SV_Q1BSP_AddToFatPVS (org, node->children[0]);
|
||
|
node = node->children[1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
Q1BSP_FatPVS
|
||
|
|
||
|
Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
|
||
|
given point.
|
||
|
=============
|
||
|
*/
|
||
|
void Q1BSP_FatPVS (vec3_t org, qboolean add)
|
||
|
{
|
||
|
fatbytes = (sv.worldmodel->numleafs+31)>>3;
|
||
|
if (!add)
|
||
|
Q_memset (fatpvs, 0, fatbytes);
|
||
|
SV_Q1BSP_AddToFatPVS (org, sv.worldmodel->nodes);
|
||
|
}
|
||
|
|
||
|
qboolean Q1BSP_EdictInFatPVS(edict_t *ent)
|
||
|
{
|
||
|
int i;
|
||
|
for (i=0 ; i < ent->num_leafs ; i++)
|
||
|
if (fatpvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
|
||
|
return true; //we might be able to see this one.
|
||
|
|
||
|
return false; //none of this ents leafs were visible, so neither is the ent.
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
SV_FindTouchedLeafs
|
||
|
|
||
|
Links the edict to the right leafs so we can get it's potential visability.
|
||
|
===============
|
||
|
*/
|
||
|
void Q1BSP_RFindTouchedLeafs (edict_t *ent, mnode_t *node)
|
||
|
{
|
||
|
mplane_t *splitplane;
|
||
|
mleaf_t *leaf;
|
||
|
int sides;
|
||
|
int leafnum;
|
||
|
|
||
|
if (node->contents == Q1CONTENTS_SOLID)
|
||
|
return;
|
||
|
|
||
|
// add an efrag if the node is a leaf
|
||
|
|
||
|
if ( node->contents < 0)
|
||
|
{
|
||
|
if (ent->num_leafs == MAX_ENT_LEAFS)
|
||
|
return;
|
||
|
|
||
|
leaf = (mleaf_t *)node;
|
||
|
leafnum = leaf - sv.worldmodel->leafs - 1;
|
||
|
|
||
|
ent->leafnums[ent->num_leafs] = leafnum;
|
||
|
ent->num_leafs++;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// NODE_MIXED
|
||
|
|
||
|
splitplane = node->plane;
|
||
|
sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);
|
||
|
|
||
|
// recurse down the contacted sides
|
||
|
if (sides & 1)
|
||
|
Q1BSP_RFindTouchedLeafs (ent, node->children[0]);
|
||
|
|
||
|
if (sides & 2)
|
||
|
Q1BSP_RFindTouchedLeafs (ent, node->children[1]);
|
||
|
}
|
||
|
void Q1BSP_FindTouchedLeafs(edict_t *ent)
|
||
|
{
|
||
|
ent->num_leafs = 0;
|
||
|
if (ent->v.modelindex)
|
||
|
Q1BSP_RFindTouchedLeafs (ent, sv.worldmodel->nodes);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Server only functions
|
||
|
|
||
|
==============================================================================
|
||
|
|
||
|
*/
|
||
|
|