2004-08-21 01:25:48 +00:00
# include "quakedef.h"
2009-11-04 21:16:50 +00:00
# include "pr_common.h"
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
qboolean Heightmap_Trace ( model_t * model , int forcehullnum , int frame , vec3_t axis [ 3 ] , vec3_t start , vec3_t end , vec3_t mins , vec3_t maxs , unsigned int contentmask , trace_t * trace ) ;
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Physics functions ( common )
*/
2010-07-12 22:46:37 +00:00
void Q1BSP_CheckHullNodes ( hull_t * hull )
{
int num , c ;
2011-06-29 18:39:11 +00:00
mclipnode_t * node ;
2010-07-12 22:46:37 +00:00
for ( num = hull - > firstclipnode ; num < hull - > lastclipnode ; num + + )
{
node = hull - > clipnodes + num ;
for ( c = 0 ; c < 2 ; c + + )
if ( node - > children [ c ] > = 0 )
if ( node - > children [ c ] < hull - > firstclipnode | | node - > children [ c ] > hull - > lastclipnode )
Sys_Error ( " Q1BSP_CheckHull: bad node number " ) ;
2011-05-19 13:34:07 +00:00
2010-07-12 22:46:37 +00:00
}
}
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_HullPointContents
= = = = = = = = = = = = = = = = = =
*/
static int Q1_HullPointContents ( hull_t * hull , int num , vec3_t p )
{
float d ;
2011-06-29 18:39:11 +00:00
mclipnode_t * node ;
2004-08-21 01:25:48 +00:00
mplane_t * plane ;
while ( num > = 0 )
{
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 ;
}
2012-05-09 15:30:53 +00:00
static int Q1_ModelPointContents ( mnode_t * node , vec3_t p )
{
float d ;
mplane_t * plane ;
while ( node - > contents > = 0 )
{
plane = node - > plane ;
if ( plane - > type < 3 )
d = p [ plane - > type ] - plane - > dist ;
else
d = DotProduct ( plane - > normal , p ) - plane - > dist ;
node = node - > children [ d < 0 ] ;
}
return node - > contents ;
}
2004-08-21 01:25:48 +00:00
# define DIST_EPSILON (0.03125)
2010-07-13 09:49:38 +00:00
#if 0
2010-07-12 22:46:37 +00:00
enum
{
rht_solid ,
rht_empty ,
rht_impact
} ;
vec3_t rht_start , rht_end ;
static int Q1BSP_RecursiveHullTrace ( hull_t * hull , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
{
2012-02-12 05:18:31 +00:00
mclipnode_t * node ;
2010-07-12 22:46:37 +00:00
mplane_t * plane ;
float t1 , t2 ;
vec3_t mid ;
int side ;
float midf ;
int rht ;
reenter :
if ( num < 0 )
{
/*hit a leaf*/
if ( num = = Q1CONTENTS_SOLID )
{
if ( trace - > allsolid )
trace - > startsolid = true ;
return rht_solid ;
}
else
{
trace - > allsolid = false ;
if ( num = = Q1CONTENTS_EMPTY )
trace - > inopen = true ;
else
trace - > inwater = true ;
return rht_empty ;
}
}
/*its a node*/
2011-05-19 13:34:07 +00:00
2010-07-12 22:46:37 +00:00
/*get the node info*/
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 ;
}
2011-05-19 13:34:07 +00:00
2010-07-12 22:46:37 +00:00
/*if its completely on one side, resume on that side*/
if ( t1 > = 0 & & t2 > = 0 )
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[0], p1f, p2f, p1, p2, trace);
num = node - > children [ 0 ] ;
goto reenter ;
}
if ( t1 < 0 & & t2 < 0 )
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[1], p1f, p2f, p1, p2, trace);
num = node - > children [ 1 ] ;
goto reenter ;
}
if ( plane - > type < 3 )
{
t1 = rht_start [ plane - > type ] - plane - > dist ;
t2 = rht_end [ plane - > type ] - plane - > dist ;
}
else
{
t1 = DotProduct ( plane - > normal , rht_start ) - plane - > dist ;
t2 = DotProduct ( plane - > normal , rht_end ) - plane - > dist ;
}
side = t1 < 0 ;
midf = t1 / ( t1 - t2 ) ;
if ( midf < p1f ) midf = p1f ;
if ( midf > p2f ) midf = p2f ;
VectorInterpolate ( rht_start , midf , rht_end , mid ) ;
rht = Q1BSP_RecursiveHullTrace ( hull , node - > children [ side ] , p1f , midf , p1 , mid , trace ) ;
if ( rht ! = rht_empty )
return rht ;
rht = Q1BSP_RecursiveHullTrace ( hull , node - > children [ side ^ 1 ] , midf , p2f , mid , p2 , trace ) ;
if ( rht ! = rht_solid )
return rht ;
2011-05-19 13:34:07 +00:00
2010-07-12 22:46:37 +00:00
if ( side )
{
/*we impacted the back of the node, so flip the plane*/
trace - > plane . dist = - plane - > dist ;
VectorNegate ( plane - > normal , trace - > plane . normal ) ;
midf = ( t1 + DIST_EPSILON ) / ( t1 - t2 ) ;
}
else
{
/*we impacted the front of the node*/
trace - > plane . dist = plane - > dist ;
VectorCopy ( plane - > normal , trace - > plane . normal ) ;
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
}
2012-02-12 05:18:31 +00:00
t1 = DotProduct ( trace - > plane . normal , rht_start ) - trace - > plane . dist ;
t2 = DotProduct ( trace - > plane . normal , rht_end ) - trace - > plane . dist ;
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
trace - > fraction = midf ;
2010-07-12 22:46:37 +00:00
VectorCopy ( mid , trace - > endpos ) ;
VectorInterpolate ( rht_start , midf , rht_end , trace - > endpos ) ;
return rht_impact ;
}
qboolean Q1BSP_RecursiveHullCheck ( hull_t * hull , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
{
if ( VectorEquals ( p1 , p2 ) )
{
/*points cannot cross planes, so do it faster*/
switch ( Q1_HullPointContents ( hull , num , p1 ) )
{
case Q1CONTENTS_SOLID :
trace - > startsolid = true ;
break ;
case Q1CONTENTS_EMPTY :
trace - > allsolid = false ;
trace - > inopen = true ;
break ;
default :
trace - > allsolid = false ;
trace - > inwater = true ;
break ;
}
return true ;
}
else
{
VectorCopy ( p1 , rht_start ) ;
VectorCopy ( p2 , rht_end ) ;
return Q1BSP_RecursiveHullTrace ( hull , num , p1f , p2f , p1 , p2 , trace ) ! = rht_impact ;
}
}
# else
2004-08-21 01:25:48 +00:00
qboolean Q1BSP_RecursiveHullCheck ( hull_t * hull , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
{
2011-06-29 18:39:11 +00:00
mclipnode_t * node ;
2004-08-21 01:25:48 +00:00
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
}
//
// 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
2008-05-25 22:23:43 +00:00
if ( ! ( frac < 10000000 ) & & ! ( frac > - 10000000 ) )
{
trace - > fraction = 0 ;
VectorClear ( trace - > endpos ) ;
Con_Printf ( " nan in traceline \n " ) ;
return false ;
}
2004-08-21 01:25:48 +00:00
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 ;
}
2010-07-12 22:46:37 +00:00
# endif
2004-08-21 01:25:48 +00:00
2012-02-27 12:23:15 +00:00
/*
the bsp tree we ' re walking through is the renderable hull
we need to trace a box through the world .
by its very nature , this will reach more nodes than we really want , and as we can follow a node sideways , the underlying bsp structure is no longer 100 % reliable ( meaning we cross planes that are entirely to one side , and follow its children too )
so all contents and solidity must come from the brushes and ONLY the brushes .
*/
struct traceinfo_s
{
unsigned int solidcontents ;
trace_t trace ;
qboolean sphere ;
float radius ;
/*set even for sphere traces (used for bbox tests)*/
vec3_t mins ;
vec3_t maxs ;
vec3_t start ;
vec3_t end ;
} ;
2012-02-27 13:55:23 +00:00
#if 0
2012-02-27 12:23:15 +00:00
# include "shader.h"
void TestDrawPlane ( float * normal , float dist , float r , float g , float b )
{
scenetris_t * t ;
if ( cl_numstris = = cl_maxstris )
{
cl_maxstris + = 8 ;
cl_stris = BZ_Realloc ( cl_stris , sizeof ( * cl_stris ) * cl_maxstris ) ;
}
t = & cl_stris [ cl_numstris + + ] ;
t - > shader = R_RegisterShader ( " testplane " , " { \n { \n map $whiteimage \n rgbgen vertex \n alphagen vertex \n blendfunc add \n nodepth \n } \n } \n " ) ;
t - > firstidx = cl_numstrisidx ;
t - > firstvert = cl_numstrisvert ;
t - > numvert = 0 ;
t - > numidx = 0 ;
if ( cl_numstrisidx + 6 > cl_maxstrisidx )
{
cl_maxstrisidx = cl_numstrisidx + 6 + 64 ;
cl_strisidx = BZ_Realloc ( cl_strisidx , sizeof ( * cl_strisidx ) * cl_maxstrisidx ) ;
}
if ( cl_numstrisvert + 4 > cl_maxstrisvert )
{
cl_maxstrisvert + = 64 ;
cl_strisvertv = BZ_Realloc ( cl_strisvertv , sizeof ( * cl_strisvertv ) * cl_maxstrisvert ) ;
cl_strisvertt = BZ_Realloc ( cl_strisvertt , sizeof ( * cl_strisvertt ) * cl_maxstrisvert ) ;
cl_strisvertc = BZ_Realloc ( cl_strisvertc , sizeof ( * cl_strisvertc ) * cl_maxstrisvert ) ;
}
{
vec3_t tmp = { 0 , 0.04 , 0.96 } ;
vec3_t right , forward ;
CrossProduct ( normal , tmp , right ) ;
VectorNormalize ( right ) ;
CrossProduct ( normal , right , forward ) ;
VectorNormalize ( forward ) ;
VectorScale ( normal , dist , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , 8192 , right , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , 8192 , forward , cl_strisvertv [ cl_numstrisvert ] ) ;
Vector4Set ( cl_strisvertc [ cl_numstrisvert ] , r , g , b , 0.2 ) ;
cl_numstrisvert + + ;
VectorScale ( normal , dist , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , 8192 , right , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , - 8192 , forward , cl_strisvertv [ cl_numstrisvert ] ) ;
Vector4Set ( cl_strisvertc [ cl_numstrisvert ] , r , g , b , 0.2 ) ;
cl_numstrisvert + + ;
VectorScale ( normal , dist , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , - 8192 , right , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , - 8192 , forward , cl_strisvertv [ cl_numstrisvert ] ) ;
Vector4Set ( cl_strisvertc [ cl_numstrisvert ] , r , g , b , 0.2 ) ;
cl_numstrisvert + + ;
VectorScale ( normal , dist , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , - 8192 , right , cl_strisvertv [ cl_numstrisvert ] ) ;
VectorMA ( cl_strisvertv [ cl_numstrisvert ] , 8192 , forward , cl_strisvertv [ cl_numstrisvert ] ) ;
Vector4Set ( cl_strisvertc [ cl_numstrisvert ] , r , g , b , 0.2 ) ;
cl_numstrisvert + + ;
}
/*build the triangles*/
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 0 ;
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 1 ;
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 2 ;
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 0 ;
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 2 ;
cl_strisidx [ cl_numstrisidx + + ] = t - > numvert + 3 ;
t - > numidx = cl_numstrisidx - t - > firstidx ;
t - > numvert + = 4 ;
}
2012-02-27 13:55:23 +00:00
# endif
2012-02-27 12:23:15 +00:00
static void Q1BSP_ClipToBrushes ( struct traceinfo_s * traceinfo , mbrush_t * brush )
{
struct mbrushplane_s * plane ;
struct mbrushplane_s * enterplane ;
int i , j ;
vec3_t ofs ;
qboolean startout , endout ;
float d1 , d2 , dist , enterdist = 0 ;
float f , enterfrac , exitfrac ;
for ( ; brush ; brush = brush - > next )
{
/*ignore if its not solid to us*/
if ( ! ( traceinfo - > solidcontents & brush - > contents ) )
continue ;
startout = false ;
endout = false ;
enterplane = NULL ;
enterfrac = - 1 ;
exitfrac = 10 ;
for ( i = brush - > numplanes , plane = brush - > planes ; i ; i - - , plane + + )
{
/*calculate the distance based upon the shape of the object we're tracing for*/
if ( traceinfo - > sphere )
{
dist = plane - > dist + traceinfo - > radius ;
}
else
{
for ( j = 0 ; j < 3 ; j + + )
{
if ( plane - > normal [ j ] < 0 )
ofs [ j ] = traceinfo - > maxs [ j ] ;
else
ofs [ j ] = traceinfo - > mins [ j ] ;
}
dist = DotProduct ( ofs , plane - > normal ) ;
dist = plane - > dist - dist ;
}
d1 = DotProduct ( traceinfo - > start , plane - > normal ) - dist ;
d2 = DotProduct ( traceinfo - > end , plane - > normal ) - dist ;
if ( d1 > = 0 )
startout = true ;
if ( d2 > 0 )
endout = true ;
//if we're fully outside any plane, then we cannot possibly enter the brush, skip to the next one
if ( d1 > 0 & & d2 > = 0 )
goto nextbrush ;
//if we're fully inside the plane, then whatever is happening is not relevent for this plane
if ( d1 < 0 & & d2 < = 0 )
continue ;
f = d1 / ( d1 - d2 ) ;
if ( d1 > d2 )
{
//entered the brush. favour the furthest fraction to avoid extended edges (yay for convex shapes)
if ( enterfrac < f )
{
enterfrac = f ;
enterplane = plane ;
enterdist = dist ;
}
}
else
{
//left the brush, favour the nearest plane (smallest frac)
if ( exitfrac > f )
{
exitfrac = f ;
}
}
}
if ( ! startout )
{
traceinfo - > trace . startsolid = true ;
if ( ! endout )
traceinfo - > trace . allsolid = true ;
traceinfo - > trace . contents | = brush - > contents ;
return ;
}
if ( enterfrac ! = - 1 & & enterfrac < exitfrac )
{
//impact!
if ( enterfrac < traceinfo - > trace . fraction )
{
traceinfo - > trace . fraction = enterfrac ;
traceinfo - > trace . plane . dist = enterdist ;
VectorCopy ( enterplane - > normal , traceinfo - > trace . plane . normal ) ;
traceinfo - > trace . contents = brush - > contents ;
}
}
nextbrush :
;
}
}
static void Q1BSP_InsertBrush ( mnode_t * node , mbrush_t * brush , vec3_t bmins , vec3_t bmaxs )
{
vec3_t near , far ;
float nd , fd ;
int i ;
while ( 1 )
{
if ( node - > contents < 0 ) /*leaf, so no smaller node to put it in (I'd be surprised if it got this far)*/
{
brush - > next = node - > brushes ;
node - > brushes = brush ;
return ;
}
for ( i = 0 ; i < 3 ; i + + )
{
if ( node - > plane - > normal [ i ] > 0 )
{
near [ i ] = bmins [ i ] ;
far [ i ] = bmaxs [ i ] ;
}
else
{
near [ i ] = bmaxs [ i ] ;
far [ i ] = bmins [ i ] ;
}
}
nd = DotProduct ( node - > plane - > normal , near ) - node - > plane - > dist ;
fd = DotProduct ( node - > plane - > normal , far ) - node - > plane - > dist ;
/*if its fully on either side, continue walking*/
if ( nd < 0 & & fd < 0 )
node = node - > children [ 1 ] ;
else if ( nd > 0 & & fd > 0 )
node = node - > children [ 0 ] ;
else
{
/*plane crosses bbox, so insert here*/
brush - > next = node - > brushes ;
node - > brushes = brush ;
return ;
}
}
}
static void Q1BSP_RecursiveBrushCheck ( struct traceinfo_s * traceinfo , mnode_t * node , float p1f , float p2f , vec3_t p1 , vec3_t p2 )
{
mplane_t * plane ;
float t1 , t2 ;
float frac ;
int i ;
vec3_t mid ;
int side ;
float midf ;
float offset ;
if ( node - > brushes )
{
Q1BSP_ClipToBrushes ( traceinfo , node - > brushes ) ;
}
if ( traceinfo - > trace . fraction < p1f )
{
//already hit something closer than this node
return ;
}
if ( node - > contents < 0 )
{
//we're in a leaf
return ;
}
//
// find the point distances
//
plane = node - > plane ;
if ( plane - > type < 3 )
{
t1 = p1 [ plane - > type ] - plane - > dist ;
t2 = p2 [ plane - > type ] - plane - > dist ;
if ( plane - > normal [ plane - > type ] < 0 )
offset = - traceinfo - > mins [ plane - > type ] ;
else
offset = traceinfo - > maxs [ plane - > type ] ;
}
else
{
t1 = DotProduct ( plane - > normal , p1 ) - plane - > dist ;
t2 = DotProduct ( plane - > normal , p2 ) - plane - > dist ;
offset = 0 ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( plane - > normal [ i ] < 0 )
offset + = plane - > normal [ i ] * - traceinfo - > mins [ i ] ;
else
offset + = plane - > normal [ i ] * traceinfo - > maxs [ i ] ;
}
}
/*if we're fully on one side of the trace, go only down that side*/
if ( t1 > = offset & & t2 > = offset )
{
Q1BSP_RecursiveBrushCheck ( traceinfo , node - > children [ 0 ] , p1f , p2f , p1 , p2 ) ;
return ;
}
if ( t1 < - offset & & t2 < - offset )
{
Q1BSP_RecursiveBrushCheck ( traceinfo , node - > children [ 1 ] , p1f , p2f , p1 , p2 ) ;
return ;
}
// put the crosspoint DIST_EPSILON pixels on the near side
if ( t1 < 0 )
{
frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 ) ;
side = 1 ;
}
else
{
frac = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
side = 0 ;
}
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 ] ) ;
// move up to the node
Q1BSP_RecursiveBrushCheck ( traceinfo , node - > children [ side ] , p1f , midf , p1 , mid ) ;
// go past the node
Q1BSP_RecursiveBrushCheck ( traceinfo , node - > children [ side ^ 1 ] , midf , p2f , mid , p2 ) ;
}
static unsigned int Q1BSP_TranslateContents ( int contents )
2004-08-21 01:25:48 +00:00
{
2012-02-27 12:23:15 +00:00
switch ( contents )
2004-08-21 01:25:48 +00:00
{
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 ;
2012-02-27 12:23:15 +00:00
case Q1CONTENTS_LADDER :
return FTECONTENTS_LADDER ;
2004-08-21 01:25:48 +00:00
default :
2012-02-27 12:23:15 +00:00
Sys_Error ( " Q1BSP_TranslateContents: Unknown contents type - %i " , contents ) ;
2004-08-21 01:25:48 +00:00
return FTECONTENTS_SOLID ;
}
}
2012-02-27 12:23:15 +00:00
int Q1BSP_HullPointContents ( hull_t * hull , vec3_t p )
{
return Q1BSP_TranslateContents ( Q1_HullPointContents ( hull , hull - > firstclipnode , p ) ) ;
}
2010-08-28 17:14:38 +00:00
unsigned int Q1BSP_PointContents ( model_t * model , vec3_t axis [ 3 ] , vec3_t point )
2005-08-26 22:56:51 +00:00
{
2010-08-28 17:14:38 +00:00
if ( axis )
{
vec3_t transformed ;
transformed [ 0 ] = DotProduct ( point , axis [ 0 ] ) ;
transformed [ 1 ] = DotProduct ( point , axis [ 1 ] ) ;
transformed [ 2 ] = DotProduct ( point , axis [ 2 ] ) ;
return Q1BSP_HullPointContents ( & model - > hulls [ 0 ] , transformed ) ;
}
2012-05-14 01:41:08 +00:00
if ( ! model - > firstmodelsurface )
2012-05-09 15:30:53 +00:00
{
return Q1BSP_TranslateContents ( Q1_ModelPointContents ( model - > nodes , point ) ) ;
}
2005-08-26 22:56:51 +00:00
return Q1BSP_HullPointContents ( & model - > hulls [ 0 ] , point ) ;
2004-08-21 01:25:48 +00:00
}
2012-02-27 12:23:15 +00:00
void Q1BSP_LoadBrushes ( model_t * model )
{
struct {
unsigned int ver ;
unsigned int modelnum ;
unsigned int numbrushes ;
unsigned int numplanes ;
} * permodel ;
struct {
float mins [ 3 ] ;
float maxs [ 3 ] ;
signed short contents ;
unsigned short numplanes ;
} * perbrush ;
/*
Note to implementors :
a pointy brush with angles pointier than 90 degrees will extend further than any adjacent brush , thus creating invisible walls with larger expansions .
the engine inserts 6 axial planes acording to the bbox , thus the qbsp need not write any axial planes
note that doing it this way probably isn ' t good if you want to query textures . . .
*/
struct {
vec3_t normal ;
float dist ;
} * perplane ;
static vec3_t axis [ 3 ] = { { 1 , 0 , 0 } , { 0 , 1 , 0 } , { 0 , 0 , 1 } } ;
int br , pl , remainingplanes ;
mbrush_t * brush ;
mnode_t * rootnode ;
unsigned int lumpsizeremaining ;
model - > engineflags & = ~ MDLF_HASBRUSHES ;
permodel = Q1BSPX_FindLump ( " BRUSHLIST " , & lumpsizeremaining ) ;
if ( ! permodel )
return ;
while ( lumpsizeremaining )
{
if ( lumpsizeremaining < sizeof ( * permodel ) )
return ;
permodel - > ver = LittleLong ( permodel - > ver ) ;
permodel - > modelnum = LittleLong ( permodel - > modelnum ) ;
permodel - > numbrushes = LittleLong ( permodel - > numbrushes ) ;
permodel - > numplanes = LittleLong ( permodel - > numplanes ) ;
if ( permodel - > ver ! = 1 | | lumpsizeremaining < sizeof ( * permodel ) + permodel - > numbrushes * sizeof ( * perbrush ) + permodel - > numplanes * sizeof ( * perplane ) )
return ;
//find the correct rootnode for the model
rootnode = model - > nodes ;
if ( permodel - > modelnum > model - > numsubmodels )
return ;
if ( permodel - > modelnum )
rootnode + = model - > submodels [ permodel - > modelnum - 1 ] . headnode [ 0 ] ;
brush = Hunk_Alloc ( ( sizeof ( * brush ) - sizeof ( brush - > planes [ 0 ] ) ) * permodel - > numbrushes + sizeof ( brush - > planes [ 0 ] ) * ( permodel - > numbrushes * 6 + permodel - > numplanes ) ) ;
remainingplanes = permodel - > numplanes ;
perbrush = ( void * ) ( permodel + 1 ) ;
for ( br = 0 ; br < permodel - > numbrushes ; br + + )
{
/*byteswap it all in place*/
perbrush - > mins [ 0 ] = LittleFloat ( perbrush - > mins [ 0 ] ) ;
perbrush - > mins [ 1 ] = LittleFloat ( perbrush - > mins [ 1 ] ) ;
perbrush - > mins [ 2 ] = LittleFloat ( perbrush - > mins [ 2 ] ) ;
perbrush - > maxs [ 0 ] = LittleFloat ( perbrush - > maxs [ 0 ] ) ;
perbrush - > maxs [ 1 ] = LittleFloat ( perbrush - > maxs [ 1 ] ) ;
perbrush - > maxs [ 2 ] = LittleFloat ( perbrush - > maxs [ 2 ] ) ;
perbrush - > contents = LittleShort ( perbrush - > contents ) ;
perbrush - > numplanes = LittleShort ( perbrush - > numplanes ) ;
/*make sure planes don't overflow*/
if ( perbrush - > numplanes > remainingplanes )
return ;
remainingplanes - = perbrush - > numplanes ;
/*set up the mbrush from the file*/
brush - > contents = Q1BSP_TranslateContents ( perbrush - > contents ) ;
brush - > numplanes = perbrush - > numplanes ;
for ( pl = 0 , perplane = ( void * ) ( perbrush + 1 ) ; pl < perbrush - > numplanes ; pl + + , perplane + + )
{
brush - > planes [ pl ] . normal [ 0 ] = LittleFloat ( perplane - > normal [ 0 ] ) ;
brush - > planes [ pl ] . normal [ 1 ] = LittleFloat ( perplane - > normal [ 1 ] ) ;
brush - > planes [ pl ] . normal [ 2 ] = LittleFloat ( perplane - > normal [ 2 ] ) ;
brush - > planes [ pl ] . dist = LittleFloat ( perplane - > dist ) ;
}
/*and add axial planes acording to the brush's bbox*/
for ( pl = 0 ; pl < 3 ; pl + + )
{
VectorCopy ( axis [ pl ] , brush - > planes [ brush - > numplanes ] . normal ) ;
brush - > planes [ brush - > numplanes ] . dist = perbrush - > maxs [ pl ] ;
brush - > numplanes + + ;
}
for ( pl = 0 ; pl < 3 ; pl + + )
{
VectorNegate ( axis [ pl ] , brush - > planes [ brush - > numplanes ] . normal ) ;
brush - > planes [ brush - > numplanes ] . dist = - perbrush - > mins [ pl ] ;
brush - > numplanes + + ;
}
/*link it in to the bsp tree*/
Q1BSP_InsertBrush ( rootnode , brush , perbrush - > mins , perbrush - > maxs ) ;
/*set up for the next brush*/
brush = ( void * ) & brush - > planes [ brush - > numplanes ] ;
perbrush = ( void * ) perplane ;
}
/*move on to the next model*/
lumpsizeremaining - = sizeof ( * permodel ) + permodel - > numbrushes * sizeof ( * perbrush ) + permodel - > numplanes * sizeof ( * perplane ) ;
permodel = ( void * ) ( ( char * ) permodel + sizeof ( * permodel ) + permodel - > numbrushes * sizeof ( * perbrush ) + permodel - > numplanes * sizeof ( * perplane ) ) ;
}
/*parsing was successful! flag it as okay*/
model - > engineflags | = MDLF_HASBRUSHES ;
}
2012-01-17 07:57:46 +00:00
qboolean Q1BSP_Trace ( model_t * model , int forcehullnum , int frame , vec3_t axis [ 3 ] , vec3_t start , vec3_t end , vec3_t mins , vec3_t maxs , unsigned int hitcontentsmask , trace_t * trace )
2005-07-16 00:53:08 +00:00
{
hull_t * hull ;
vec3_t size ;
vec3_t start_l , end_l ;
vec3_t offset ;
2012-02-27 12:23:15 +00:00
VectorSubtract ( maxs , mins , size ) ;
if ( ( model - > engineflags & MDLF_HASBRUSHES ) ) // && (size[0] || size[1] || size[2]))
{
struct traceinfo_s traceinfo ;
memset ( & traceinfo . trace , 0 , sizeof ( trace_t ) ) ;
traceinfo . trace . fraction = 1 ;
traceinfo . trace . allsolid = false ;
VectorCopy ( mins , traceinfo . mins ) ;
VectorCopy ( maxs , traceinfo . maxs ) ;
VectorCopy ( start , traceinfo . start ) ;
VectorCopy ( end , traceinfo . end ) ;
traceinfo . sphere = false ;
/* traceinfo.sphere = true;
traceinfo . radius = 48 ;
traceinfo . mins [ 0 ] = - traceinfo . radius ;
traceinfo . mins [ 1 ] = - traceinfo . radius ;
traceinfo . mins [ 2 ] = - traceinfo . radius ;
traceinfo . maxs [ 0 ] = traceinfo . radius ;
traceinfo . maxs [ 1 ] = traceinfo . radius ;
traceinfo . maxs [ 2 ] = traceinfo . radius ;
*/
traceinfo . solidcontents = hitcontentsmask ;
Q1BSP_RecursiveBrushCheck ( & traceinfo , model - > nodes , 0 , 1 , start , end ) ;
memcpy ( trace , & traceinfo . trace , sizeof ( trace_t ) ) ;
if ( trace - > fraction < 1 )
{
float d1 = DotProduct ( start , trace - > plane . normal ) - trace - > plane . dist ;
float d2 = DotProduct ( end , trace - > plane . normal ) - trace - > plane . dist ;
float f = ( d1 - DIST_EPSILON ) / ( d1 - d2 ) ;
if ( f < 0 )
f = 0 ;
trace - > fraction = f ;
}
VectorInterpolate ( start , trace - > fraction , end , trace - > endpos ) ;
return trace - > fraction ! = 1 ;
}
2005-07-16 00:53:08 +00:00
memset ( trace , 0 , sizeof ( trace_t ) ) ;
trace - > fraction = 1 ;
trace - > allsolid = true ;
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 ] ;
2012-02-12 05:18:31 +00:00
else if ( size [ 0 ] < = 8.1 & & model - > hulls [ 4 ] . available )
2010-08-18 21:59:06 +00:00
hull = & model - > hulls [ 4 ] ; //Pentacles
2012-02-12 05:18:31 +00:00
else if ( size [ 0 ] < = 32.1 & & size [ 2 ] < = 28.1 ) // Half Player
2005-07-16 00:53:08 +00:00
hull = & model - > hulls [ 3 ] ;
2012-02-12 05:18:31 +00:00
else if ( size [ 0 ] < = 32.1 ) // Full Player
2005-07-16 00:53:08 +00:00
hull = & model - > hulls [ 1 ] ;
else // Golumn
hull = & model - > hulls [ 5 ] ;
}
else
{
if ( size [ 0 ] < 3 | | ! model - > hulls [ 1 ] . available )
hull = & model - > hulls [ 0 ] ;
2012-02-12 05:18:31 +00:00
else if ( size [ 0 ] < = 32.1 )
2005-07-16 00:53:08 +00:00
{
2012-02-12 05:18:31 +00:00
if ( size [ 2 ] < 54.1 & & model - > hulls [ 3 ] . available )
2005-07-16 00:53:08 +00:00
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 ) ;
2010-08-28 17:14:38 +00:00
if ( axis )
2005-07-16 00:53:08 +00:00
{
2010-08-28 17:14:38 +00:00
vec3_t tmp ;
VectorSubtract ( start , offset , tmp ) ;
start_l [ 0 ] = DotProduct ( tmp , axis [ 0 ] ) ;
start_l [ 1 ] = DotProduct ( tmp , axis [ 1 ] ) ;
start_l [ 2 ] = DotProduct ( tmp , axis [ 2 ] ) ;
VectorSubtract ( end , offset , tmp ) ;
end_l [ 0 ] = DotProduct ( tmp , axis [ 0 ] ) ;
end_l [ 1 ] = DotProduct ( tmp , axis [ 1 ] ) ;
end_l [ 2 ] = DotProduct ( tmp , axis [ 2 ] ) ;
Q1BSP_RecursiveHullCheck ( hull , hull - > firstclipnode , 0 , 1 , start_l , end_l , trace ) ;
if ( trace - > fraction = = 1 )
{
VectorCopy ( end , trace - > endpos ) ;
}
else
{
vec3_t iaxis [ 3 ] ;
vec3_t norm ;
2011-07-30 14:14:56 +00:00
Matrix3x3_RM_Invert_Simple ( ( void * ) axis , iaxis ) ;
2010-08-28 17:14:38 +00:00
VectorCopy ( trace - > plane . normal , norm ) ;
trace - > plane . normal [ 0 ] = DotProduct ( norm , iaxis [ 0 ] ) ;
trace - > plane . normal [ 1 ] = DotProduct ( norm , iaxis [ 1 ] ) ;
trace - > plane . normal [ 2 ] = DotProduct ( norm , iaxis [ 2 ] ) ;
/*just interpolate it, its easier than inverse matrix rotations*/
VectorInterpolate ( start , trace - > fraction , end , trace - > endpos ) ;
}
2005-07-16 00:53:08 +00:00
}
else
{
2010-08-28 17:14:38 +00:00
VectorSubtract ( start , offset , start_l ) ;
VectorSubtract ( end , offset , end_l ) ;
Q1BSP_RecursiveHullCheck ( hull , hull - > firstclipnode , 0 , 1 , start_l , end_l , trace ) ;
2011-05-19 13:34:07 +00:00
2010-08-28 17:14:38 +00:00
if ( trace - > fraction = = 1 )
{
VectorCopy ( end , trace - > endpos ) ;
}
else
{
VectorAdd ( trace - > endpos , offset , trace - > endpos ) ;
}
2005-07-16 00:53:08 +00:00
}
2012-07-15 03:18:34 +00:00
# ifdef TERRAIN
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
if ( model - > terrain & & trace - > fraction )
{
trace_t hmt ;
Heightmap_Trace ( model , forcehullnum , frame , axis , start , end , mins , maxs , hitcontentsmask , & hmt ) ;
if ( hmt . fraction < trace - > fraction )
* trace = hmt ;
}
2012-07-15 03:18:34 +00:00
# endif
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
2005-07-16 00:53:08 +00:00
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
2009-07-14 15:13:12 +00:00
float l , maxdist ;
int j , s , t ;
vec3_t impact ;
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 ;
2009-07-14 15:13:12 +00:00
if ( splitplane - > type < 3 )
dist = light - > origin [ splitplane - > type ] - splitplane - > dist ;
else
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
2009-07-14 15:13:12 +00:00
maxdist = light - > radius * light - > radius ;
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 + + )
{
2009-07-14 15:13:12 +00:00
//Yeah, you can blame LordHavoc for this alternate code here.
for ( j = 0 ; j < 3 ; j + + )
impact [ j ] = light - > origin [ j ] - surf - > plane - > normal [ j ] * dist ;
// clamp center of light to corner and check brightness
l = DotProduct ( impact , surf - > texinfo - > vecs [ 0 ] ) + surf - > texinfo - > vecs [ 0 ] [ 3 ] - surf - > texturemins [ 0 ] ;
s = l + 0.5 ; if ( s < 0 ) s = 0 ; else if ( s > surf - > extents [ 0 ] ) s = surf - > extents [ 0 ] ;
s = l - s ;
l = DotProduct ( impact , surf - > texinfo - > vecs [ 1 ] ) + surf - > texinfo - > vecs [ 1 ] [ 3 ] - surf - > texturemins [ 1 ] ;
t = l + 0.5 ; if ( t < 0 ) t = 0 ; else if ( t > surf - > extents [ 1 ] ) t = surf - > extents [ 1 ] ;
t = l - t ;
// compare to minimum light
if ( ( s * s + t * t + dist * dist ) < maxdist )
2004-08-21 01:25:48 +00:00
{
2009-07-14 15:13:12 +00:00
if ( surf - > dlightframe ! = r_dlightframecount )
{
surf - > dlightbits = bit ;
surf - > dlightframe = r_dlightframecount ;
}
else
surf - > dlightbits | = bit ;
2004-08-21 01:25:48 +00:00
}
}
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 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
2009-10-06 00:33:54 +00:00
# define MAXFRAGMENTVERTS 360
2005-05-13 10:42:48 +00:00
int Fragment_ClipPolyToPlane ( float * inverts , float * outverts , int incount , float * plane , float planedist )
{
2010-07-11 02:22:39 +00:00
# define C 4
2009-10-06 00:33:54 +00:00
float dotv [ MAXFRAGMENTVERTS + 1 ] ;
char keep [ MAXFRAGMENTVERTS + 1 ] ;
# define KEEP_KILL 0
# define KEEP_KEEP 1
2011-05-19 13:34:07 +00:00
# define KEEP_BORDER 2
2009-10-06 00:33:54 +00:00
int i ;
2005-05-13 10:42:48 +00:00
int outcount = 0 ;
int clippedcount = 0 ;
2009-10-06 00:33:54 +00:00
float d , * p1 , * p2 , * out ;
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 + + )
{
2010-07-11 02:22:39 +00:00
dotv [ i ] = DotProduct ( ( inverts + i * C ) , plane ) - planedist ;
2005-09-08 22:52:46 +00:00
if ( dotv [ i ] < - FRAG_EPSILON )
2005-05-13 10:42:48 +00:00
{
2009-10-06 00:33:54 +00:00
keep [ i ] = KEEP_KILL ;
clippedcount + + ;
2005-05-13 10:42:48 +00:00
}
2009-10-06 00:33:54 +00:00
else if ( dotv [ i ] > FRAG_EPSILON )
keep [ i ] = KEEP_KEEP ;
else
keep [ i ] = KEEP_BORDER ;
2005-05-13 10:42:48 +00:00
}
2009-10-06 00:33:54 +00:00
dotv [ i ] = dotv [ 0 ] ;
keep [ i ] = keep [ 0 ] ;
2005-05-13 10:42:48 +00:00
if ( clippedcount = = incount )
return 0 ; //all were clipped
if ( clippedcount = = 0 )
2005-09-08 22:52:46 +00:00
{ //none were clipped
2010-07-11 02:22:39 +00:00
for ( i = 0 ; i < incount ; i + + )
VectorCopy ( ( inverts + i * C ) , ( outverts + i * C ) ) ;
2005-05-13 10:42:48 +00:00
return incount ;
}
2009-10-06 00:33:54 +00:00
for ( i = 0 ; i < incount ; i + + )
2005-05-13 10:42:48 +00:00
{
2010-07-11 02:22:39 +00:00
p1 = inverts + i * C ;
2009-10-06 00:33:54 +00:00
if ( keep [ i ] = = KEEP_BORDER )
2005-05-13 10:42:48 +00:00
{
2010-07-11 02:22:39 +00:00
out = outverts + outcount + + * C ;
2009-10-06 00:33:54 +00:00
VectorCopy ( p1 , out ) ;
continue ;
2005-05-13 10:42:48 +00:00
}
2009-10-06 00:33:54 +00:00
if ( keep [ i ] = = KEEP_KEEP )
{
2010-07-11 02:22:39 +00:00
out = outverts + outcount + + * C ;
2009-10-06 00:33:54 +00:00
VectorCopy ( p1 , out ) ;
2005-05-13 10:42:48 +00:00
}
2009-10-06 00:33:54 +00:00
if ( keep [ i + 1 ] = = KEEP_BORDER | | keep [ i ] = = keep [ i + 1 ] )
continue ;
2010-07-11 02:22:39 +00:00
p2 = inverts + ( ( i + 1 ) % incount ) * C ;
2009-10-06 00:33:54 +00:00
d = dotv [ i ] - dotv [ i + 1 ] ;
if ( d )
d = dotv [ i ] / d ;
2010-07-11 02:22:39 +00:00
out = outverts + outcount + + * C ;
2009-10-06 00:33:54 +00:00
VectorInterpolate ( p1 , d , p2 , out ) ;
2005-05-13 10:42:48 +00:00
}
return outcount ;
}
2009-10-06 00:33:54 +00:00
void Fragment_ClipPoly ( fragmentdecal_t * dec , int numverts , float * inverts )
2005-05-13 10:42:48 +00:00
{
//emit the triangle, and clip it's fragments.
int p ;
2010-07-11 02:22:39 +00:00
float verts [ MAXFRAGMENTVERTS * C ] ;
float verts2 [ MAXFRAGMENTVERTS * C ] ;
2005-09-08 22:52:46 +00:00
float * cverts ;
int flip ;
2005-05-13 10:42:48 +00:00
2009-10-06 00:33:54 +00:00
if ( numverts > MAXFRAGMENTTRIS )
return ;
2005-05-13 10:42:48 +00:00
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ; //don't bother
2009-10-06 00:33:54 +00:00
//clip to the first plane specially, so we don't have extra copys
numverts = Fragment_ClipPolyToPlane ( inverts , verts , numverts , dec - > planenorm [ 0 ] , dec - > planedist [ 0 ] ) ;
2005-05-13 10:42:48 +00:00
//clip the triangle to the 6 planes.
2005-09-08 22:52:46 +00:00
flip = 0 ;
2009-10-06 00:33:54 +00:00
for ( p = 1 ; 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 - - ;
2010-07-11 02:22:39 +00:00
VectorCopy ( ( cverts + C * 0 ) , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( ( cverts + C * ( numverts - 1 ) ) , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( ( cverts + C * 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 ;
2010-07-11 02:22:39 +00:00
vecV_t verts [ 3 ] ;
2009-10-06 00:33:54 +00:00
/*if its a triangle fan/poly/quad then we can just submit the entire thing without generating extra fragments*/
2009-11-04 21:16:50 +00:00
if ( mesh - > istrifan )
2009-10-06 00:33:54 +00:00
{
Fragment_ClipPoly ( dec , mesh - > numvertexes , mesh - > xyz_array [ 0 ] ) ;
return ;
}
2009-11-04 21:16:50 +00:00
//Fixme: optimise q3 patches (quad strips with bends between each strip)
2005-05-13 10:42:48 +00:00
2009-10-06 00:33:54 +00:00
/*otherwise it goes in and out in weird places*/
2005-05-13 10:42:48 +00:00
for ( i = 0 ; i < mesh - > numindexes ; i + = 3 )
{
if ( dec - > numtris = = MAXFRAGMENTTRIS )
break ;
2009-10-06 00:33:54 +00:00
VectorCopy ( mesh - > xyz_array [ mesh - > indexes [ i + 0 ] ] , verts [ 0 ] ) ;
VectorCopy ( mesh - > xyz_array [ mesh - > indexes [ i + 1 ] ] , verts [ 1 ] ) ;
VectorCopy ( mesh - > xyz_array [ mesh - > indexes [ i + 2 ] ] , verts [ 2 ] ) ;
Fragment_ClipPoly ( dec , 3 , verts [ 0 ] ) ;
2005-05-13 10:42:48 +00:00
}
}
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 ] ) ;
}
2009-11-04 21:16:50 +00:00
# ifdef RTLIGHTS
extern int sh_shadowframe ;
# else
static int sh_shadowframe ;
# endif
# ifdef Q3BSPS
2009-10-06 00:33:54 +00:00
void Q3BSP_ClipDecalToNodes ( fragmentdecal_t * dec , mnode_t * node )
{
mplane_t * splitplane ;
float dist ;
msurface_t * * msurf ;
msurface_t * surf ;
mleaf_t * leaf ;
int i ;
if ( node - > contents ! = - 1 )
{
leaf = ( mleaf_t * ) node ;
// mark the polygons
msurf = leaf - > firstmarksurface ;
for ( i = 0 ; i < leaf - > nummarksurfaces ; i + + , msurf + + )
{
surf = * msurf ;
2009-11-04 21:16:50 +00:00
//only check each surface once. it can appear in multiple leafs.
if ( surf - > shadowframe = = sh_shadowframe )
continue ;
surf - > shadowframe = sh_shadowframe ;
2009-10-06 00:33:54 +00:00
Fragment_Mesh ( dec , surf - > mesh ) ;
}
return ;
}
splitplane = node - > plane ;
dist = DotProduct ( dec - > center , splitplane - > normal ) - splitplane - > dist ;
if ( dist > dec - > radius )
{
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
return ;
}
if ( dist < - dec - > radius )
{
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
return ;
}
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
}
2009-11-04 21:16:50 +00:00
# endif
2009-10-06 00:33:54 +00:00
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
2009-11-04 21:16:50 +00:00
sh_shadowframe + + ;
2011-06-29 18:39:11 +00:00
if ( ! cl . worldmodel )
return 0 ;
else if ( cl . worldmodel - > fromgame = = fg_quake )
2009-10-06 00:33:54 +00:00
Q1BSP_ClipDecalToNodes ( & dec , cl . worldmodel - > nodes ) ;
2009-11-04 21:16:50 +00:00
# ifdef Q3BSPS
else if ( cl . worldmodel - > fromgame = = fg_quake3 )
Q3BSP_ClipDecalToNodes ( & dec , cl . worldmodel - > nodes ) ;
# endif
2005-05-13 10:42:48 +00:00
* 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
/*
2009-10-06 00:33:54 +00:00
# include "glquake.h"
2005-05-13 10:42:48 +00:00
void Q1BSP_TestClipDecal ( void )
{
int i ;
int numtris ;
vec3_t fwd ;
vec3_t start ;
2009-10-06 00:33:54 +00:00
vec3_t center , normal , tangent , tangent2 ;
2005-05-13 10:42:48 +00:00
float * verts ;
if ( cls . state ! = ca_active )
return ;
2009-10-06 00:33:54 +00:00
VectorCopy ( r_origin , start ) ;
// start[2]+=22;
2005-05-13 10:42:48 +00:00
VectorMA ( start , 10000 , vpn , fwd ) ;
2009-10-06 00:33:54 +00:00
if ( ! TraceLineN ( start , fwd , center , normal ) )
{
VectorCopy ( start , center ) ;
normal [ 0 ] = 0 ;
normal [ 1 ] = 0 ;
normal [ 2 ] = 1 ;
}
2005-05-13 10:42:48 +00:00
CrossProduct ( fwd , normal , tangent ) ;
VectorNormalize ( tangent ) ;
2009-10-06 00:33:54 +00:00
CrossProduct ( normal , tangent , tangent2 ) ;
numtris = Q1BSP_ClipDecal ( center , normal , tangent , tangent2 , 128 , & verts ) ;
PPL_RevertToKnownState ( ) ;
2005-05-13 10:42:48 +00:00
qglDisable ( GL_TEXTURE_2D ) ;
qglDisable ( GL_BLEND ) ;
2009-10-06 00:33:54 +00:00
qglDisable ( GL_ALPHA_TEST ) ;
2005-05-13 10:42:48 +00:00
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 ) ;
2009-10-06 00:33:54 +00:00
PPL_RevertToKnownState ( ) ;
2005-05-13 10:42:48 +00:00
}
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
//does the recursive work of Q1BSP_FatPVS
2009-06-21 17:45:33 +00:00
void SV_Q1BSP_AddToFatPVS ( model_t * mod , vec3_t org , mnode_t * node , qbyte * buffer , unsigned int buffersize )
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 )
{
2009-07-11 20:56:09 +00:00
pvs = Q1BSP_LeafPVS ( mod , ( mleaf_t * ) node , NULL , 0 ) ;
2009-06-21 17:45:33 +00:00
for ( i = 0 ; i < buffersize ; i + + )
buffer [ i ] | = pvs [ i ] ;
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
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
2009-06-21 17:45:33 +00:00
SV_Q1BSP_AddToFatPVS ( mod , org , node - > children [ 0 ] , buffer , buffersize ) ;
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 .
= = = = = = = = = = = = =
*/
2009-06-23 21:49:44 +00:00
unsigned int Q1BSP_FatPVS ( model_t * mod , vec3_t org , qbyte * pvsbuffer , unsigned int buffersize , qboolean add )
2004-08-21 01:25:48 +00:00
{
2009-06-21 17:45:33 +00:00
unsigned int fatbytes = ( mod - > numleafs + 31 ) > > 3 ;
if ( fatbytes > buffersize )
Sys_Error ( " map had too much pvs data (too many leaves) \n " ) ; ;
2004-08-21 01:25:48 +00:00
if ( ! add )
2009-06-21 17:45:33 +00:00
Q_memset ( pvsbuffer , 0 , fatbytes ) ;
SV_Q1BSP_AddToFatPVS ( mod , org , mod - > nodes , pvsbuffer , fatbytes ) ;
2009-06-23 21:49:44 +00:00
return fatbytes ;
2004-08-21 01:25:48 +00:00
}
2011-01-29 19:53:38 +00:00
# endif
2010-07-11 02:22:39 +00:00
qboolean Q1BSP_EdictInFatPVS ( model_t * mod , struct pvscache_s * ent , qbyte * pvs )
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 + + )
2009-06-21 17:45:33 +00:00
if ( pvs [ ent - > leafnums [ i ] > > 3 ] & ( 1 < < ( ent - > leafnums [ i ] & 7 ) ) )
2004-08-21 01:25:48 +00:00
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 .
= = = = = = = = = = = = = = =
*/
2010-07-11 02:22:39 +00:00
void Q1BSP_RFindTouchedLeafs ( model_t * wm , struct pvscache_s * ent , mnode_t * node , float * mins , float * maxs )
2004-08-21 01:25:48 +00:00
{
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 ;
2010-07-11 02:22:39 +00:00
leafnum = leaf - wm - > leafs - 1 ;
2004-08-21 01:25:48 +00:00
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 ;
2009-03-03 01:52:30 +00:00
sides = BOX_ON_PLANE_SIDE ( mins , maxs , 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 )
2010-07-11 02:22:39 +00:00
Q1BSP_RFindTouchedLeafs ( wm , ent , node - > children [ 0 ] , mins , maxs ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
if ( sides & 2 )
2010-07-11 02:22:39 +00:00
Q1BSP_RFindTouchedLeafs ( wm , ent , node - > children [ 1 ] , mins , maxs ) ;
2004-08-21 01:25:48 +00:00
}
2010-07-11 02:22:39 +00:00
void Q1BSP_FindTouchedLeafs ( model_t * mod , struct pvscache_s * ent , float * mins , float * maxs )
2004-08-21 01:25:48 +00:00
{
ent - > num_leafs = 0 ;
2010-07-11 02:22:39 +00:00
if ( mins & & maxs )
Q1BSP_RFindTouchedLeafs ( mod , ent , mod - > nodes , mins , maxs ) ;
2004-08-21 01:25:48 +00:00
}
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
= = = = = = = = = = = = = = = = = = =
*/
2009-07-11 20:56:09 +00:00
qbyte * Q1BSP_DecompressVis ( qbyte * in , model_t * model , qbyte * decompressed , unsigned int buffersize )
2005-08-26 22:56:51 +00:00
{
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 ;
2009-07-11 20:56:09 +00:00
if ( buffersize < row )
row = buffersize ;
2005-08-26 22:56:51 +00:00
#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 ] ;
2009-07-11 20:56:09 +00:00
qbyte * Q1BSP_LeafPVS ( model_t * model , mleaf_t * leaf , qbyte * buffer , unsigned int buffersize )
2005-08-26 22:56:51 +00:00
{
static qbyte decompressed [ MAX_MAP_LEAFS / 8 ] ;
if ( leaf = = model - > leafs )
return mod_novis ;
if ( ! buffer )
2009-07-11 20:56:09 +00:00
{
2005-08-26 22:56:51 +00:00
buffer = decompressed ;
2009-07-11 20:56:09 +00:00
buffersize = sizeof ( decompressed ) ;
}
2005-08-26 22:56:51 +00:00
2009-07-11 20:56:09 +00:00
return Q1BSP_DecompressVis ( leaf - > compressed_vis , model , buffer , buffersize ) ;
2005-08-26 22:56:51 +00:00
}
2009-07-11 20:56:09 +00:00
qbyte * Q1BSP_LeafnumPVS ( model_t * model , int leafnum , qbyte * buffer , unsigned int buffersize )
2005-08-26 22:56:51 +00:00
{
2009-07-11 20:56:09 +00:00
return Q1BSP_LeafPVS ( model , model - > leafs + leafnum , buffer , buffersize ) ;
2005-08-26 22:56:51 +00:00
}
//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
*/
2012-02-27 12:23:15 +00:00
2005-08-26 22:56:51 +00:00
void Q1BSP_Init ( void )
{
memset ( mod_novis , 0xff , sizeof ( mod_novis ) ) ;
}
2012-02-27 12:23:15 +00:00
typedef struct {
char lumpname [ 24 ] ; // up to 23 chars, zero-padded
int fileofs ; // from file start
int filelen ;
} bspx_lump_t ;
typedef struct {
char id [ 4 ] ; // 'BSPX'
int numlumps ;
bspx_lump_t lumps [ 1 ] ;
} bspx_header_t ;
static char * bspxbase ;
static bspx_header_t * bspxheader ;
//supported lumps:
//RGBLIGHTING (.lit)
//LIGHTINGDIR (.lux)
void * Q1BSPX_FindLump ( char * lumpname , int * lumpsize )
{
int i ;
2012-06-01 12:57:01 +00:00
* lumpsize = 0 ;
2012-02-27 12:23:15 +00:00
if ( ! bspxheader )
return NULL ;
for ( i = 0 ; i < bspxheader - > numlumps ; i + + )
{
if ( ! strncmp ( bspxheader - > lumps [ i ] . lumpname , lumpname , 24 ) )
{
* lumpsize = bspxheader - > lumps [ i ] . filelen ;
return bspxbase + bspxheader - > lumps [ i ] . fileofs ;
}
}
return NULL ;
}
void Q1BSPX_Setup ( model_t * mod , char * filebase , unsigned int filelen , lump_t * lumps , int numlumps )
{
int i ;
int offs = 0 ;
bspx_header_t * h ;
bspxbase = filebase ;
bspxheader = NULL ;
for ( i = 0 ; i < numlumps ; i + + , lumps + + )
{
if ( offs < lumps - > fileofs + lumps - > filelen )
offs = lumps - > fileofs + lumps - > filelen ;
}
offs = ( offs + 3 ) & ~ 3 ;
if ( offs + sizeof ( * bspxheader ) > filelen )
return ; /*no space for it*/
h = ( bspx_header_t * ) ( filebase + offs ) ;
i = LittleLong ( h - > numlumps ) ;
/*verify the header*/
if ( * ( int * ) h - > id ! = * ( int * ) " BSPX " | |
i < 0 | |
offs + sizeof ( * h ) + sizeof ( h - > lumps [ 0 ] ) * ( i - 1 ) > filelen )
return ;
h - > numlumps = i ;
while ( i - - > 0 )
{
h - > lumps [ i ] . fileofs = LittleLong ( h - > lumps [ i ] . fileofs ) ;
h - > lumps [ i ] . filelen = LittleLong ( h - > lumps [ i ] . filelen ) ;
if ( h - > lumps [ i ] . fileofs + h - > lumps [ i ] . filelen > filelen )
return ;
}
bspxheader = h ;
}
2005-08-26 22:56:51 +00:00
//sets up the functions a server needs.
//fills in bspfuncs_t
void Q1BSP_SetModelFuncs ( model_t * mod )
{
# ifndef CLIENTONLY
mod - > funcs . FatPVS = Q1BSP_FatPVS ;
2011-01-29 19:53:38 +00:00
# endif
2005-08-26 22:56:51 +00:00
mod - > funcs . EdictInFatPVS = Q1BSP_EdictInFatPVS ;
2010-07-11 02:22:39 +00:00
mod - > funcs . FindTouchedLeafs = Q1BSP_FindTouchedLeafs ;
2005-08-26 22:56:51 +00:00
mod - > funcs . LightPointValues = NULL ;
mod - > funcs . StainNode = NULL ;
mod - > funcs . MarkLights = NULL ;
mod - > funcs . LeafnumForPoint = Q1BSP_LeafnumForPoint ;
mod - > funcs . LeafPVS = Q1BSP_LeafnumPVS ;
2012-01-17 07:57:46 +00:00
mod - > funcs . NativeTrace = Q1BSP_Trace ;
2005-08-26 22:56:51 +00:00
mod - > funcs . PointContents = Q1BSP_PointContents ;
2006-03-04 20:43:48 +00:00
}