2004-08-21 01:25:48 +00:00
# include "quakedef.h"
2005-08-26 22:56:51 +00:00
qbyte * Q1BSP_LeafPVS ( model_t * model , mleaf_t * leaf , qbyte * buffer ) ;
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 )
2005-01-28 20:19:01 +00:00
Sys_Error ( " SV_HullPointContents: bad node number " ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
node = hull - > clipnodes + num ;
plane = hull - > planes + node - > planenum ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
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 ] ;
}
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
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 )
2004-12-05 16:47:58 +00:00
Sys_Error ( " Q1BSP_RecursiveHullCheck: bad node number " ) ;
2004-08-21 01:25:48 +00:00
//
// 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 ;
}
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
# 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
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
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 ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
if ( trace - > allsolid )
return false ; // never got out of the solid area
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
//==================
// 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
{
2006-05-29 04:50:24 +00:00
VectorNegate ( plane - > normal , trace - > plane . normal ) ;
2004-08-21 01:25:48 +00:00
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 )
{
2005-08-26 22:56:51 +00:00
// hull->funcs.HullPointContents = Q1BSP_HullPointContents;
}
2006-03-04 20:43:48 +00:00
unsigned int Q1BSP_PointContents ( model_t * model , vec3_t point )
2005-08-26 22:56:51 +00:00
{
return Q1BSP_HullPointContents ( & model - > hulls [ 0 ] , point ) ;
2004-08-21 01:25:48 +00:00
}
2005-07-16 00:53:08 +00:00
qboolean Q1BSP_Trace ( model_t * model , int forcehullnum , int frame , vec3_t start , vec3_t end , vec3_t mins , vec3_t maxs , trace_t * trace )
{
hull_t * hull ;
vec3_t size ;
vec3_t start_l , end_l ;
vec3_t offset ;
memset ( trace , 0 , sizeof ( trace_t ) ) ;
trace - > fraction = 1 ;
trace - > allsolid = true ;
VectorSubtract ( maxs , mins , size ) ;
if ( forcehullnum > = 1 & & forcehullnum < = MAX_MAP_HULLSM & & model - > hulls [ forcehullnum - 1 ] . available )
hull = & model - > hulls [ forcehullnum - 1 ] ;
else
{
if ( model - > hulls [ 5 ] . available )
{ //choose based on hexen2 sizes.
if ( size [ 0 ] < 3 ) // Point
hull = & model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 32 & & size [ 2 ] < = 28 ) // Half Player
hull = & model - > hulls [ 3 ] ;
else if ( size [ 0 ] < = 32 ) // Full Player
hull = & model - > hulls [ 1 ] ;
else // Golumn
hull = & model - > hulls [ 5 ] ;
}
else
{
if ( size [ 0 ] < 3 | | ! model - > hulls [ 1 ] . available )
hull = & model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 32 )
{
if ( size [ 2 ] < 54 & & model - > hulls [ 3 ] . available )
hull = & model - > hulls [ 3 ] ; // 32x32x36 (half-life's crouch)
else
hull = & model - > hulls [ 1 ] ;
}
else
hull = & model - > hulls [ 2 ] ;
}
}
// calculate an offset value to center the origin
VectorSubtract ( hull - > clip_mins , mins , offset ) ;
VectorSubtract ( start , offset , start_l ) ;
VectorSubtract ( end , offset , end_l ) ;
Q1BSP_RecursiveHullCheck ( hull , hull - > firstclipnode , 0 , 1 , start_l , end_l , trace ) ;
if ( trace - > fraction = = 1 )
{
VectorCopy ( end , trace - > endpos ) ;
}
else
{
VectorAdd ( trace - > endpos , offset , trace - > endpos ) ;
}
return trace - > fraction ! = 1 ;
}
2004-08-21 01:25:48 +00:00
/*
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 ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
if ( node - > contents < 0 )
2006-03-04 20:43:48 +00:00
return ;
2004-08-21 01:25:48 +00:00
splitplane = node - > plane ;
dist = DotProduct ( light - > origin , splitplane - > normal ) - splitplane - > dist ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
if ( dist > light - > radius )
{
Q1BSP_MarkLights ( light , bit , node - > children [ 0 ] ) ;
return ;
}
if ( dist < - light - > radius )
{
Q1BSP_MarkLights ( light , bit , node - > children [ 1 ] ) ;
return ;
}
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
// mark the polygons
2005-10-16 04:03:13 +00:00
surf = currentmodel - > surfaces + node - > firstsurface ;
2004-08-21 01:25:48 +00:00
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 ] ) ;
}
2005-05-13 10:42:48 +00:00
# define MAXFRAGMENTTRIS 256
vec3_t decalfragmentverts [ MAXFRAGMENTTRIS * 3 ] ;
typedef struct {
vec3_t center ;
vec3_t normal ;
2005-09-08 22:52:46 +00:00
// vec3_t tangent1;
// vec3_t tangent2;
2005-05-13 10:42:48 +00:00
vec3_t planenorm [ 6 ] ;
float planedist [ 6 ] ;
2005-09-08 22:52:46 +00:00
int numplanes ;
2005-05-13 10:42:48 +00:00
vec_t radius ;
int numtris ;
} fragmentdecal_t ;
# define FloatInterpolate(a, bness, b, c) (c) = (a)*(1-bness) + (b)*bness
# define VectorInterpolate(a, bness, b, c) FloatInterpolate((a)[0], bness, (b)[0], (c)[0]),FloatInterpolate((a)[1], bness, (b)[1], (c)[1]),FloatInterpolate((a)[2], bness, (b)[2], (c)[2])
//#define SHOWCLIPS
//#define FRAGMENTASTRIANGLES //works, but produces more fragments.
# ifdef FRAGMENTASTRIANGLES
//if the triangle is clipped away, go recursive if there are tris left.
void Fragment_ClipTriToPlane ( int trinum , float * plane , float planedist , fragmentdecal_t * dec )
{
float * point [ 3 ] ;
float dotv [ 3 ] ;
vec3_t impact1 , impact2 ;
float t ;
int i , i2 , i3 ;
int clippedverts = 0 ;
for ( i = 0 ; i < 3 ; i + + )
{
point [ i ] = decalfragmentverts [ trinum * 3 + i ] ;
dotv [ i ] = DotProduct ( point [ i ] , plane ) - planedist ;
clippedverts + = dotv [ i ] < 0 ;
}
//if they're all clipped away, scrap the tri
switch ( clippedverts )
{
case 0 :
return ; //plane does not clip the triangle.
case 1 : //split into 3, disregard the clipped vert
for ( i = 0 ; i < 3 ; i + + )
{
if ( dotv [ i ] < 0 )
{ //This is the vertex that's getting clipped.
if ( dotv [ i ] > - DIST_EPSILON )
return ; //it's only over the line by a tiny ammount.
i2 = ( i + 1 ) % 3 ;
i3 = ( i + 2 ) % 3 ;
if ( dotv [ i2 ] < DIST_EPSILON )
return ;
if ( dotv [ i3 ] < DIST_EPSILON )
return ;
//work out where the two lines impact the plane
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i2 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i2 ] , impact1 ) ;
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i3 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i3 ] , impact2 ) ;
# ifdef SHOWCLIPS
if ( dec - > numtris ! = MAXFRAGMENTTRIS )
{
VectorCopy ( impact2 , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( decalfragmentverts [ trinum * 3 + i ] , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( impact1 , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
}
# endif
//shrink the tri, putting the impact into the killed vertex.
VectorCopy ( impact2 , point [ i ] ) ;
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ; //:(
//build the second tri
VectorCopy ( impact1 , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( decalfragmentverts [ trinum * 3 + i2 ] , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( impact2 , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
return ;
}
}
Sys_Error ( " Fragment_ClipTriToPlane: Clipped vertex not founc \n " ) ;
return ; //can't handle it
case 2 : //split into 3, disregarding both the clipped.
for ( i = 0 ; i < 3 ; i + + )
{
if ( ! ( dotv [ i ] < 0 ) )
{ //This is the vertex that's staying.
if ( dotv [ i ] < DIST_EPSILON )
break ; //only just inside
i2 = ( i + 1 ) % 3 ;
i3 = ( i + 2 ) % 3 ;
//work out where the two lines impact the plane
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i2 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i2 ] , impact1 ) ;
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i3 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i3 ] , impact2 ) ;
//shrink the tri, putting the impact into the killed vertex.
# ifdef SHOWCLIPS
if ( dec - > numtris ! = MAXFRAGMENTTRIS )
{
VectorCopy ( impact1 , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( point [ i2 ] , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( point [ i3 ] , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
}
if ( dec - > numtris ! = MAXFRAGMENTTRIS )
{
VectorCopy ( impact1 , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( point [ i3 ] , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( impact2 , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
}
# endif
VectorCopy ( impact1 , point [ i2 ] ) ;
VectorCopy ( impact2 , point [ i3 ] ) ;
return ;
}
}
case 3 : //scrap it
//fill the verts with the verts of the last and go recursive (due to the nature of Fragment_ClipTriangle, which doesn't actually know if we clip them away)
# ifndef SHOWCLIPS
dec - > numtris - - ;
VectorCopy ( decalfragmentverts [ dec - > numtris * 3 + 0 ] , decalfragmentverts [ trinum * 3 + 0 ] ) ;
VectorCopy ( decalfragmentverts [ dec - > numtris * 3 + 1 ] , decalfragmentverts [ trinum * 3 + 1 ] ) ;
VectorCopy ( decalfragmentverts [ dec - > numtris * 3 + 2 ] , decalfragmentverts [ trinum * 3 + 2 ] ) ;
if ( trinum < dec - > numtris )
Fragment_ClipTriToPlane ( trinum , plane , planedist , dec ) ;
# endif
return ;
}
}
void Fragment_ClipTriangle ( fragmentdecal_t * dec , float * a , float * b , float * c )
{
//emit the triangle, and clip it's fragments.
int start , i ;
int p ;
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ; //:(
start = dec - > numtris ;
VectorCopy ( a , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( b , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( c , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
//clip all the fragments to all of the planes.
//This will produce a quad if the source triangle was big enough.
for ( p = 0 ; p < 6 ; p + + )
{
for ( i = start ; i < dec - > numtris ; i + + )
Fragment_ClipTriToPlane ( i , dec - > planenorm [ p ] , dec - > plantdist [ p ] , dec ) ;
}
}
# else
# define MAXFRAGMENTVERTS 128
int Fragment_ClipPolyToPlane ( float * inverts , float * outverts , int incount , float * plane , float planedist )
{
float dotv [ MAXFRAGMENTVERTS ] ;
int i , i2 , i3 ;
int outcount = 0 ;
int clippedcount = 0 ;
vec3_t impact ;
2005-06-14 04:52:10 +00:00
float * lastvalid = NULL ; //the reason these arn't just an index is because it'd need to be a special case for the first vert.
float lastvaliddot = 0 ;
2005-09-08 22:52:46 +00:00
# define FRAG_EPSILON 0.5
2005-05-13 10:42:48 +00:00
for ( i = 0 ; i < incount ; i + + )
{
dotv [ i ] = DotProduct ( ( inverts + i * 3 ) , plane ) - planedist ;
2005-09-08 22:52:46 +00:00
if ( dotv [ i ] < - FRAG_EPSILON )
2005-05-13 10:42:48 +00:00
clippedcount + + ;
else
{
lastvalid = inverts + i * 3 ;
lastvaliddot = dotv [ i ] ;
}
}
if ( clippedcount = = incount )
return 0 ; //all were clipped
if ( clippedcount = = 0 )
2005-09-08 22:52:46 +00:00
{ //none were clipped
2005-05-13 10:42:48 +00:00
memcpy ( outverts , inverts , sizeof ( float ) * 3 * incount ) ;
return incount ;
}
2005-09-08 22:52:46 +00:00
//FIXME:
/*
We should end up with a nicly clipped quad .
If a vertex is on the other side of the place , we remove it , and add two in it ' s place , on the lines between the verts not chopped .
we work out the last remaining vert in the above loop
the loop below loops through all verts , if it ' s to be removed , it does a nested loop to find the next vert that is not going to be removed
it then adds two new verts on the right two lines .
Due to using four clipplanes , this should result in a perfect quad . It doesn ' t .
*/
2005-05-13 10:42:48 +00:00
for ( i = 0 ; i < incount ; )
{
2005-09-08 22:52:46 +00:00
if ( dotv [ i ] < - FRAG_EPSILON ) //clipped
2005-05-13 10:42:48 +00:00
{
//work out where the line impacts the plane
lastvaliddot = ( dotv [ i ] ) / ( dotv [ i ] - lastvaliddot ) ;
VectorInterpolate ( ( inverts + i * 3 ) , lastvaliddot , lastvalid , impact ) ;
if ( outcount + 1 > = MAXFRAGMENTVERTS ) //bum
break ;
2005-09-08 22:52:46 +00:00
//generate a vertex where the line crosses the plane
2005-05-13 10:42:48 +00:00
outverts [ outcount * 3 + 0 ] = impact [ 0 ] ;
outverts [ outcount * 3 + 1 ] = impact [ 1 ] ;
outverts [ outcount * 3 + 2 ] = impact [ 2 ] ;
outcount + + ;
i3 = ( i + 1 ) ;
2005-09-08 22:52:46 +00:00
while ( dotv [ i3 % incount ] < - FRAG_EPSILON ) //clipped
2005-05-13 10:42:48 +00:00
i3 + + ;
2005-09-08 22:52:46 +00:00
//take away any verticies on the other side of the plane
2005-05-13 10:42:48 +00:00
i = ( i3 - 1 ) % incount ;
i2 = i3 % incount ;
lastvaliddot = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i2 ] ) ;
VectorInterpolate ( ( inverts + i * 3 ) , lastvaliddot , ( inverts + i2 * 3 ) , impact ) ;
2005-09-08 22:52:46 +00:00
//generate a vertex where the line crosses back onto our plane
2005-05-13 10:42:48 +00:00
outverts [ outcount * 3 + 0 ] = impact [ 0 ] ;
outverts [ outcount * 3 + 1 ] = impact [ 1 ] ;
outverts [ outcount * 3 + 2 ] = impact [ 2 ] ;
outcount + + ;
lastvalid = outverts + outcount * 3 ;
lastvaliddot = 0 ; // :)
i = i3 ;
}
else
{ //this vertex wasn't clipped. Just copy to the output.
if ( outcount = = MAXFRAGMENTVERTS ) //bum
break ;
outverts [ outcount * 3 + 0 ] = inverts [ i * 3 + 0 ] ;
outverts [ outcount * 3 + 1 ] = inverts [ i * 3 + 1 ] ;
outverts [ outcount * 3 + 2 ] = inverts [ i * 3 + 2 ] ;
lastvalid = inverts + i * 3 ;
lastvaliddot = dotv [ i ] ;
outcount + + ;
i + + ;
}
}
return outcount ;
}
void Fragment_ClipTriangle ( fragmentdecal_t * dec , float * a , float * b , float * c )
{
//emit the triangle, and clip it's fragments.
int p ;
float verts [ MAXFRAGMENTVERTS * 3 ] ;
float verts2 [ MAXFRAGMENTVERTS * 3 ] ;
2005-09-08 22:52:46 +00:00
float * cverts ;
2005-05-13 10:42:48 +00:00
int numverts ;
2005-09-08 22:52:46 +00:00
int flip ;
2005-05-13 10:42:48 +00:00
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ; //don't bother
VectorCopy ( a , ( verts + 0 * 3 ) ) ;
VectorCopy ( b , ( verts + 1 * 3 ) ) ;
VectorCopy ( c , ( verts + 2 * 3 ) ) ;
numverts = 3 ;
//clip the triangle to the 6 planes.
2005-09-08 22:52:46 +00:00
flip = 0 ;
for ( p = 0 ; p < dec - > numplanes ; p + + )
2005-05-13 10:42:48 +00:00
{
2005-09-08 22:52:46 +00:00
flip ^ = 1 ;
if ( flip )
numverts = Fragment_ClipPolyToPlane ( verts , verts2 , numverts , dec - > planenorm [ p ] , dec - > planedist [ p ] ) ;
else
numverts = Fragment_ClipPolyToPlane ( verts2 , verts , numverts , dec - > planenorm [ p ] , dec - > planedist [ p ] ) ;
2005-05-13 10:42:48 +00:00
if ( numverts < 3 ) //totally clipped.
return ;
}
2005-09-08 22:52:46 +00:00
if ( flip )
cverts = verts2 ;
else
cverts = verts ;
2005-05-13 10:42:48 +00:00
//decompose the resultant polygon into triangles.
while ( numverts > 2 )
{
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ;
numverts - - ;
2005-09-08 22:52:46 +00:00
VectorCopy ( ( cverts + 3 * 0 ) , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( ( cverts + 3 * ( numverts - 1 ) ) , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( ( cverts + 3 * numverts ) , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
2005-05-13 10:42:48 +00:00
dec - > numtris + + ;
}
}
# endif
//this could be inlined, but I'm lazy.
2005-09-08 22:52:46 +00:00
void Fragment_Mesh ( fragmentdecal_t * dec , mesh_t * mesh )
2005-05-13 10:42:48 +00:00
{
int i ;
float * a , * b , * c ;
for ( i = 0 ; i < mesh - > numindexes ; i + = 3 )
{
if ( dec - > numtris = = MAXFRAGMENTTRIS )
break ;
a = mesh - > xyz_array [ mesh - > indexes [ i + 0 ] ] ;
b = mesh - > xyz_array [ mesh - > indexes [ i + 1 ] ] ;
c = mesh - > xyz_array [ mesh - > indexes [ i + 2 ] ] ;
Fragment_ClipTriangle ( dec , a , b , c ) ;
}
}
void Q1BSP_ClipDecalToNodes ( fragmentdecal_t * dec , mnode_t * node )
{
mplane_t * splitplane ;
float dist ;
msurface_t * surf ;
int i ;
2006-03-04 20:43:48 +00:00
2005-05-13 10:42:48 +00:00
if ( node - > contents < 0 )
2006-03-04 20:43:48 +00:00
return ;
2005-05-13 10:42:48 +00:00
splitplane = node - > plane ;
dist = DotProduct ( dec - > center , splitplane - > normal ) - splitplane - > dist ;
if ( dist > dec - > radius )
{
Q1BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
return ;
}
if ( dist < - dec - > radius )
{
Q1BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
return ;
}
// mark the polygons
surf = cl . worldmodel - > surfaces + node - > firstsurface ;
for ( i = 0 ; i < node - > numsurfaces ; i + + , surf + + )
{
2005-06-04 04:20:20 +00:00
if ( surf - > flags & SURF_PLANEBACK )
{
2005-09-07 01:05:27 +00:00
if ( - DotProduct ( surf - > plane - > normal , dec - > normal ) > - 0.5 )
2005-06-04 04:20:20 +00:00
continue ;
}
else
{
2005-09-07 01:05:27 +00:00
if ( DotProduct ( surf - > plane - > normal , dec - > normal ) > - 0.5 )
2005-06-04 04:20:20 +00:00
continue ;
}
2005-09-08 22:52:46 +00:00
Fragment_Mesh ( dec , surf - > mesh ) ;
2005-05-13 10:42:48 +00:00
}
Q1BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
Q1BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
}
2005-09-08 22:52:46 +00:00
int Q1BSP_ClipDecal ( vec3_t center , vec3_t normal , vec3_t tangent1 , vec3_t tangent2 , float size , float * * out )
2005-05-13 10:42:48 +00:00
{ //quad marks a full, independant quad
int p ;
fragmentdecal_t dec ;
VectorCopy ( center , dec . center ) ;
VectorCopy ( normal , dec . normal ) ;
dec . radius = size / 2 ;
dec . numtris = 0 ;
2005-09-08 22:52:46 +00:00
VectorCopy ( tangent1 , dec . planenorm [ 0 ] ) ;
VectorNegate ( tangent1 , dec . planenorm [ 1 ] ) ;
VectorCopy ( tangent2 , dec . planenorm [ 2 ] ) ;
VectorNegate ( tangent2 , dec . planenorm [ 3 ] ) ;
2005-05-13 10:42:48 +00:00
VectorCopy ( dec . normal , dec . planenorm [ 4 ] ) ;
VectorNegate ( dec . normal , dec . planenorm [ 5 ] ) ;
for ( p = 0 ; p < 6 ; p + + )
dec . planedist [ p ] = - ( dec . radius - DotProduct ( dec . center , dec . planenorm [ p ] ) ) ;
2005-09-08 22:52:46 +00:00
dec . numplanes = 6 ;
2005-05-13 10:42:48 +00:00
Q1BSP_ClipDecalToNodes ( & dec , cl . worldmodel - > nodes ) ;
* out = ( float * ) decalfragmentverts ;
return dec . numtris ;
}
//This is spike's testing function, and is only usable by gl. :)
2006-02-11 14:51:36 +00:00
/*
2005-05-13 10:42:48 +00:00
void Q1BSP_TestClipDecal ( void )
{
int i ;
int numtris ;
vec3_t fwd ;
vec3_t start ;
vec3_t center , normal , tangent ;
float * verts ;
if ( cls . state ! = ca_active )
return ;
VectorCopy ( cl . simorg [ 0 ] , start ) ;
start [ 2 ] + = 22 ;
VectorMA ( start , 10000 , vpn , fwd ) ;
TraceLineN ( start , fwd , center , normal ) ;
CrossProduct ( fwd , normal , tangent ) ;
VectorNormalize ( tangent ) ;
numtris = Q1BSP_ClipDecal ( center , normal , tangent , 128 , & verts ) ;
qglDisable ( GL_TEXTURE_2D ) ;
qglDisable ( GL_BLEND ) ;
qglDisable ( GL_DEPTH_TEST ) ;
qglColor3f ( 1 , 0 , 0 ) ;
qglShadeModel ( GL_SMOOTH ) ;
qglBegin ( GL_TRIANGLES ) ;
for ( i = 0 ; i < numtris ; i + + )
{
qglVertex3fv ( verts + i * 9 + 0 ) ;
qglVertex3fv ( verts + i * 9 + 3 ) ;
qglVertex3fv ( verts + i * 9 + 6 ) ;
}
qglEnd ( ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglBegin ( GL_LINES ) ;
for ( i = 0 ; i < numtris ; i + + )
{
qglVertex3fv ( verts + i * 9 + 0 ) ;
qglVertex3fv ( verts + i * 9 + 3 ) ;
qglVertex3fv ( verts + i * 9 + 3 ) ;
qglVertex3fv ( verts + i * 9 + 6 ) ;
qglVertex3fv ( verts + i * 9 + 6 ) ;
qglVertex3fv ( verts + i * 9 + 0 ) ;
}
qglVertex3fv ( center ) ;
VectorMA ( center , 10 , normal , fwd ) ;
qglVertex3fv ( fwd ) ;
qglColor3f ( 0 , 1 , 0 ) ;
qglVertex3fv ( center ) ;
VectorMA ( center , 10 , tangent , fwd ) ;
qglVertex3fv ( fwd ) ;
qglColor3f ( 0 , 0 , 1 ) ;
qglVertex3fv ( center ) ;
CrossProduct ( tangent , normal , fwd ) ;
VectorMA ( center , 10 , fwd , fwd ) ;
qglVertex3fv ( fwd ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglEnd ( ) ;
qglEnable ( GL_TEXTURE_2D ) ;
qglEnable ( GL_DEPTH_TEST ) ;
}
2006-02-11 14:51:36 +00:00
*/
2005-05-13 10:42:48 +00:00
2004-08-21 01:25:48 +00:00
# endif
/*
Rendering functions ( Client only )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Server only functions
*/
2004-11-29 01:21:00 +00:00
# ifndef CLIENTONLY
2004-08-21 01:25:48 +00:00
extern int fatbytes ;
extern qbyte fatpvs [ ( MAX_MAP_LEAFS + 1 ) / 4 ] ;
//does the recursive work of Q1BSP_FatPVS
2005-08-26 22:56:51 +00:00
void SV_Q1BSP_AddToFatPVS ( model_t * mod , vec3_t org , mnode_t * node )
2004-08-21 01:25:48 +00:00
{
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 )
{
2005-08-26 22:56:51 +00:00
pvs = Q1BSP_LeafPVS ( mod , ( mleaf_t * ) node , NULL ) ;
2004-08-21 01:25:48 +00:00
for ( i = 0 ; i < fatbytes ; i + + )
fatpvs [ i ] | = pvs [ i ] ;
}
return ;
}
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
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
2005-08-26 22:56:51 +00:00
SV_Q1BSP_AddToFatPVS ( mod , org , node - > children [ 0 ] ) ;
2004-08-21 01:25:48 +00:00
node = node - > children [ 1 ] ;
}
}
}
/*
= = = = = = = = = = = = =
Q1BSP_FatPVS
Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
given point .
= = = = = = = = = = = = =
*/
2005-08-26 22:56:51 +00:00
void Q1BSP_FatPVS ( model_t * mod , vec3_t org , qboolean add )
2004-08-21 01:25:48 +00:00
{
2005-08-26 22:56:51 +00:00
fatbytes = ( mod - > numleafs + 31 ) > > 3 ;
2004-08-21 01:25:48 +00:00
if ( ! add )
Q_memset ( fatpvs , 0 , fatbytes ) ;
2005-08-26 22:56:51 +00:00
SV_Q1BSP_AddToFatPVS ( mod , org , mod - > nodes ) ;
2004-08-21 01:25:48 +00:00
}
2005-08-26 22:56:51 +00:00
qboolean Q1BSP_EdictInFatPVS ( model_t * mod , edict_t * ent )
2004-08-21 01:25:48 +00:00
{
int i ;
2005-05-13 10:42:48 +00:00
if ( ent - > num_leafs = = MAX_ENT_LEAFS + 1 )
return true ; //it's in too many leafs for us to cope with. Just trivially accept it.
2004-08-21 01:25:48 +00:00
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.
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
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 ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
// add an efrag if the node is a leaf
if ( node - > contents < 0 )
{
2005-05-13 10:42:48 +00:00
if ( ent - > num_leafs > = MAX_ENT_LEAFS )
{
ent - > num_leafs = MAX_ENT_LEAFS + 1 ; //too many. mark it as such so we can trivially accept huge mega-big brush models.
2004-08-21 01:25:48 +00:00
return ;
2005-05-13 10:42:48 +00:00
}
2004-08-21 01:25:48 +00:00
leaf = ( mleaf_t * ) node ;
leafnum = leaf - sv . worldmodel - > leafs - 1 ;
ent - > leafnums [ ent - > num_leafs ] = leafnum ;
2006-03-04 20:43:48 +00:00
ent - > num_leafs + + ;
2004-08-21 01:25:48 +00:00
return ;
}
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
// NODE_MIXED
splitplane = node - > plane ;
2005-03-28 00:11:59 +00:00
sides = BOX_ON_PLANE_SIDE ( ent - > v - > absmin , ent - > v - > absmax , splitplane ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
// recurse down the contacted sides
if ( sides & 1 )
Q1BSP_RFindTouchedLeafs ( ent , node - > children [ 0 ] ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
if ( sides & 2 )
Q1BSP_RFindTouchedLeafs ( ent , node - > children [ 1 ] ) ;
}
2005-08-26 22:56:51 +00:00
void Q1BSP_FindTouchedLeafs ( model_t * mod , edict_t * ent )
2004-08-21 01:25:48 +00:00
{
ent - > num_leafs = 0 ;
2005-03-28 00:11:59 +00:00
if ( ent - > v - > modelindex )
2005-08-26 22:56:51 +00:00
Q1BSP_RFindTouchedLeafs ( ent , mod - > nodes ) ;
2004-08-21 01:25:48 +00:00
}
2004-11-29 01:21:00 +00:00
# endif
2005-08-26 22:56:51 +00:00
2004-08-21 01:25:48 +00:00
/*
Server only functions
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2005-08-26 22:56:51 +00:00
PVS type stuff
*/
/*
= = = = = = = = = = = = = = = = = = =
Mod_DecompressVis
= = = = = = = = = = = = = = = = = = =
*/
qbyte * Q1BSP_DecompressVis ( qbyte * in , model_t * model , qbyte * decompressed )
{
int c ;
qbyte * out ;
int row ;
2006-03-04 20:43:48 +00:00
row = ( model - > numleafs + 7 ) > > 3 ;
2005-08-26 22:56:51 +00:00
out = decompressed ;
#if 0
memcpy ( out , in , row ) ;
# else
if ( ! in )
{ // no vis info, so make all visible
while ( row )
{
* out + + = 0xff ;
row - - ;
}
2006-03-04 20:43:48 +00:00
return decompressed ;
2005-08-26 22:56:51 +00:00
}
do
{
if ( * in )
{
* out + + = * in + + ;
continue ;
}
2006-03-04 20:43:48 +00:00
2005-08-26 22:56:51 +00:00
c = in [ 1 ] ;
in + = 2 ;
while ( c )
{
* out + + = 0 ;
c - - ;
}
} while ( out - decompressed < row ) ;
# endif
2006-03-04 20:43:48 +00:00
2005-08-26 22:56:51 +00:00
return decompressed ;
}
static qbyte mod_novis [ MAX_MAP_LEAFS / 8 ] ;
qbyte * Q1BSP_LeafPVS ( model_t * model , mleaf_t * leaf , qbyte * buffer )
{
static qbyte decompressed [ MAX_MAP_LEAFS / 8 ] ;
if ( leaf = = model - > leafs )
return mod_novis ;
if ( ! buffer )
buffer = decompressed ;
return Q1BSP_DecompressVis ( leaf - > compressed_vis , model , buffer ) ;
}
qbyte * Q1BSP_LeafnumPVS ( model_t * model , int leafnum , qbyte * buffer )
{
return Q1BSP_LeafPVS ( model , model - > leafs + leafnum , buffer ) ;
}
//returns the leaf number, which is used as a bit index into the pvs.
int Q1BSP_LeafnumForPoint ( model_t * model , vec3_t p )
{
mnode_t * node ;
float d ;
mplane_t * plane ;
2006-03-04 20:43:48 +00:00
2005-08-26 22:56:51 +00:00
if ( ! model )
2006-03-04 20:43:48 +00:00
{
2005-08-26 22:56:51 +00:00
Sys_Error ( " Mod_PointInLeaf: bad model " ) ;
}
if ( ! model - > nodes )
return 0 ;
node = model - > nodes ;
while ( 1 )
{
if ( node - > contents < 0 )
return ( mleaf_t * ) node - model - > leafs ;
plane = node - > plane ;
d = DotProduct ( p , plane - > normal ) - plane - > dist ;
if ( d > 0 )
node = node - > children [ 0 ] ;
else
node = node - > children [ 1 ] ;
}
2006-03-04 20:43:48 +00:00
2005-08-26 22:56:51 +00:00
return 0 ; // never reached
}
mleaf_t * Q1BSP_LeafForPoint ( model_t * model , vec3_t p )
{
return model - > leafs + Q1BSP_LeafnumForPoint ( model , p ) ;
}
/*
PVS type stuff
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Init stuff
2004-08-21 01:25:48 +00:00
*/
2005-08-26 22:56:51 +00:00
void Q1BSP_Init ( void )
{
memset ( mod_novis , 0xff , sizeof ( mod_novis ) ) ;
}
//sets up the functions a server needs.
//fills in bspfuncs_t
void Q1BSP_SetModelFuncs ( model_t * mod )
{
# ifndef CLIENTONLY
mod - > funcs . FatPVS = Q1BSP_FatPVS ;
mod - > funcs . EdictInFatPVS = Q1BSP_EdictInFatPVS ;
mod - > funcs . FindTouchedLeafs_Q1 = Q1BSP_FindTouchedLeafs ;
# endif
mod - > funcs . LightPointValues = NULL ;
mod - > funcs . StainNode = NULL ;
mod - > funcs . MarkLights = NULL ;
mod - > funcs . LeafnumForPoint = Q1BSP_LeafnumForPoint ;
mod - > funcs . LeafPVS = Q1BSP_LeafnumPVS ;
mod - > funcs . Trace = Q1BSP_Trace ;
mod - > funcs . PointContents = Q1BSP_PointContents ;
2006-03-04 20:43:48 +00:00
}