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
2016-07-12 00:40:13 +00:00
# include "shader.h"
2021-04-14 05:21:04 +00:00
# include "com_bih.h"
2016-07-12 00:40:13 +00:00
extern cvar_t r_decal_noperpendicular ;
2019-10-07 04:51:17 +00:00
extern cvar_t mod_loadsurfenvmaps ;
2021-06-01 09:23:42 +00:00
extern cvar_t mod_loadmappackages ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
/*
Decal functions
2004-08-21 01:25:48 +00:00
*/
2017-01-13 00:39:50 +00:00
# define MAXFRAGMENTVERTS 360
int Fragment_ClipPolyToPlane ( float * inverts , float * outverts , int incount , float * plane , float planedist )
2010-07-12 22:46:37 +00:00
{
2020-04-26 01:31:00 +00:00
# define C (sizeof(vecV_t) / sizeof(vec_t))
2017-01-13 00:39:50 +00:00
float dotv [ MAXFRAGMENTVERTS + 1 ] ;
char keep [ MAXFRAGMENTVERTS + 1 ] ;
# define KEEP_KILL 0
# define KEEP_KEEP 1
# define KEEP_BORDER 2
int i ;
int outcount = 0 ;
int clippedcount = 0 ;
float d , * p1 , * p2 , * out ;
# define FRAG_EPSILON (1.0 / 32) //0.5
2011-05-19 13:34:07 +00:00
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < incount ; i + + )
{
dotv [ i ] = DotProduct ( ( inverts + i * C ) , plane ) - planedist ;
if ( dotv [ i ] < - FRAG_EPSILON )
{
keep [ i ] = KEEP_KILL ;
clippedcount + + ;
}
else if ( dotv [ i ] > FRAG_EPSILON )
keep [ i ] = KEEP_KEEP ;
else
keep [ i ] = KEEP_BORDER ;
2010-07-12 22:46:37 +00:00
}
2017-01-13 00:39:50 +00:00
dotv [ i ] = dotv [ 0 ] ;
keep [ i ] = keep [ 0 ] ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
if ( clippedcount = = incount )
return 0 ; //all were clipped
if ( clippedcount = = 0 )
{ //none were clipped
for ( i = 0 ; i < incount ; i + + )
VectorCopy ( ( inverts + i * C ) , ( outverts + i * C ) ) ;
return incount ;
}
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < incount ; i + + )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
p1 = inverts + i * C ;
if ( keep [ i ] = = KEEP_BORDER )
{
out = outverts + outcount + + * C ;
VectorCopy ( p1 , out ) ;
continue ;
}
if ( keep [ i ] = = KEEP_KEEP )
{
out = outverts + outcount + + * C ;
VectorCopy ( p1 , out ) ;
}
if ( keep [ i + 1 ] = = KEEP_BORDER | | keep [ i ] = = keep [ i + 1 ] )
continue ;
p2 = inverts + ( ( i + 1 ) % incount ) * C ;
d = dotv [ i ] - dotv [ i + 1 ] ;
if ( d )
d = dotv [ i ] / d ;
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
out = outverts + outcount + + * C ;
VectorInterpolate ( p1 , d , p2 , out ) ;
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
return outcount ;
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
//the plane itself must be a vec4_t, but can have other data packed between
size_t Fragment_ClipPlaneToBrush ( vecV_t * points , size_t maxpoints , void * planes , size_t planestride , size_t numplanes , vec4_t face )
2012-05-09 15:30:53 +00:00
{
2017-01-13 00:39:50 +00:00
int p , a ;
vec4_t verts [ MAXFRAGMENTVERTS ] ;
vec4_t verts2 [ MAXFRAGMENTVERTS ] ;
vec4_t * cverts ;
int flip ;
// vec3_t d1, d2, n;
size_t numverts ;
//generate some huge quad/poly aligned with the plane
vec3_t tmp ;
vec3_t right , forward ;
double t ;
float * plane ;
2020-10-26 06:30:35 +00:00
2017-01-13 00:39:50 +00:00
// if (face[2] != 1)
// return 0;
2012-05-09 15:30:53 +00:00
2017-01-13 00:39:50 +00:00
t = fabs ( face [ 2 ] ) ;
if ( t > fabs ( face [ 0 ] ) & & t > fabs ( face [ 1 ] ) )
VectorSet ( tmp , 1 , 0 , 0 ) ;
else
VectorSet ( tmp , 0 , 0 , 1 ) ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
CrossProduct ( face , tmp , right ) ;
VectorNormalize ( right ) ;
CrossProduct ( face , right , forward ) ;
VectorNormalize ( forward ) ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
VectorScale ( face , face [ 3 ] , verts [ 0 ] ) ;
VectorMA ( verts [ 0 ] , 32767 , right , verts [ 0 ] ) ;
VectorMA ( verts [ 0 ] , 32767 , forward , verts [ 0 ] ) ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
VectorScale ( face , face [ 3 ] , verts [ 1 ] ) ;
VectorMA ( verts [ 1 ] , 32767 , right , verts [ 1 ] ) ;
VectorMA ( verts [ 1 ] , - 32767 , forward , verts [ 1 ] ) ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
VectorScale ( face , face [ 3 ] , verts [ 2 ] ) ;
VectorMA ( verts [ 2 ] , - 32767 , right , verts [ 2 ] ) ;
VectorMA ( verts [ 2 ] , - 32767 , forward , verts [ 2 ] ) ;
VectorScale ( face , face [ 3 ] , verts [ 3 ] ) ;
VectorMA ( verts [ 3 ] , - 32767 , right , verts [ 3 ] ) ;
VectorMA ( verts [ 3 ] , 32767 , forward , verts [ 3 ] ) ;
numverts = 4 ;
//clip the quad to the various other planes
flip = 0 ;
for ( p = 0 ; p < numplanes ; p + + )
2010-07-12 22:46:37 +00:00
{
2017-01-13 00:39:50 +00:00
plane = ( float * ) ( ( qbyte * ) planes + p * planestride ) ;
if ( plane ! = face )
2010-07-12 22:46:37 +00:00
{
2017-01-13 00:39:50 +00:00
vec3_t norm ;
flip ^ = 1 ;
VectorNegate ( plane , norm ) ;
if ( flip )
numverts = Fragment_ClipPolyToPlane ( ( float * ) verts , ( float * ) verts2 , numverts , norm , - plane [ 3 ] ) ;
2010-07-12 22:46:37 +00:00
else
2017-01-13 00:39:50 +00:00
numverts = Fragment_ClipPolyToPlane ( ( float * ) verts2 , ( float * ) verts , numverts , norm , - plane [ 3 ] ) ;
2020-10-26 06:30:35 +00:00
2017-01-13 00:39:50 +00:00
if ( numverts < 3 ) //totally clipped.
return 0 ;
2010-07-12 22:46:37 +00:00
}
}
2017-01-13 00:39:50 +00:00
if ( numverts > maxpoints )
return 0 ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
if ( flip )
cverts = verts2 ;
2010-07-12 22:46:37 +00:00
else
2017-01-13 00:39:50 +00:00
cverts = verts ;
for ( p = 0 ; p < numverts ; p + + )
2010-07-12 22:46:37 +00:00
{
2017-01-13 00:39:50 +00:00
for ( a = 0 ; a < 3 ; a + + )
{
float f = cverts [ p ] [ a ] ;
int rounded = floor ( f + 0.5 ) ;
//if its within 1/1000th of a qu, just round it.
if ( fabs ( f - rounded ) < 0.001 )
points [ p ] [ a ] = rounded ;
else
points [ p ] [ a ] = f ;
}
2010-07-12 22:46:37 +00:00
}
2011-05-19 13:34:07 +00:00
2017-01-13 00:39:50 +00:00
return numverts ;
}
2010-07-12 22:46:37 +00:00
2021-12-20 10:06:09 +00:00
# ifdef HAVE_CLIENT
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
# define MAXFRAGMENTTRIS 256
vec3_t decalfragmentverts [ MAXFRAGMENTTRIS * 3 ] ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
struct fragmentdecal_s
{
vec3_t center ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
vec3_t normal ;
// vec3_t tangent1;
// vec3_t tangent2;
2011-05-19 13:34:07 +00:00
2017-01-13 00:39:50 +00:00
vec3_t planenorm [ 6 ] ;
float planedist [ 6 ] ;
int numplanes ;
2012-02-12 05:18:31 +00:00
2017-01-13 00:39:50 +00:00
vec_t radius ;
2012-02-12 05:18:31 +00:00
2017-01-13 00:39:50 +00:00
//will only appear on surfaces with the matching surfaceflag
unsigned int surfflagmask ;
unsigned int surfflagmatch ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
void ( * callback ) ( void * ctx , vec3_t * fte_restrict points , size_t numpoints , shader_t * shader ) ;
void * ctx ;
} ;
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
//#define SHOWCLIPS
//#define FRAGMENTASTRIANGLES //works, but produces more fragments.
2010-07-12 22:46:37 +00:00
2017-01-13 00:39:50 +00:00
# ifdef FRAGMENTASTRIANGLES
//if the triangle is clipped away, go recursive if there are tris left.
static void Fragment_ClipTriToPlane ( int trinum , float * plane , float planedist , fragmentdecal_t * dec )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
float * point [ 3 ] ;
float dotv [ 3 ] ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
vec3_t impact1 , impact2 ;
float t ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
int i , i2 , i3 ;
int clippedverts = 0 ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < 3 ; i + + )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
point [ i ] = decalfragmentverts [ trinum * 3 + i ] ;
dotv [ i ] = DotProduct ( point [ i ] , plane ) - planedist ;
clippedverts + = dotv [ i ] < 0 ;
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
//if they're all clipped away, scrap the tri
switch ( clippedverts )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
case 0 :
return ; //plane does not clip the triangle.
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
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.
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
if ( dotv [ i ] > - DIST_EPSILON )
return ; //it's only over the line by a tiny ammount.
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
i2 = ( i + 1 ) % 3 ;
i3 = ( i + 2 ) % 3 ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
if ( dotv [ i2 ] < DIST_EPSILON )
return ;
if ( dotv [ i3 ] < DIST_EPSILON )
return ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
//work out where the two lines impact the plane
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i2 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i2 ] , impact1 ) ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
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 + + ;
}
2004-08-21 01:25:48 +00:00
# endif
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
//shrink the tri, putting the impact into the killed vertex.
VectorCopy ( impact2 , point [ i ] ) ;
2006-03-04 20:43:48 +00:00
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
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 ;
}
2008-05-25 22:23:43 +00:00
}
2017-01-13 00:39:50 +00:00
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 + + )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
if ( ! ( dotv [ i ] < 0 ) )
{ //This is the vertex that's staying.
2015-03-05 22:14:21 +00:00
2017-01-13 00:39:50 +00:00
if ( dotv [ i ] < DIST_EPSILON )
break ; //only just inside
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
i2 = ( i + 1 ) % 3 ;
i3 = ( i + 2 ) % 3 ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
//work out where the two lines impact the plane
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i2 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i2 ] , impact1 ) ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
t = ( dotv [ i ] ) / ( dotv [ i ] - dotv [ i3 ] ) ;
VectorInterpolate ( point [ i ] , t , point [ i3 ] , impact2 ) ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
//shrink the tri, putting the impact into the killed vertex.
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
# ifdef SHOWCLIPS
if ( dec - > numtris ! = MAXFRAGMENTTRIS )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
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 + + ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
if ( dec - > numtris ! = MAXFRAGMENTTRIS )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
VectorCopy ( impact1 , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( point [ i3 ] , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( impact2 , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
# endif
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
VectorCopy ( impact1 , point [ i2 ] ) ;
VectorCopy ( impact2 , point [ i3 ] ) ;
return ;
2012-02-27 12:23:15 +00:00
}
}
2017-01-13 00:39:50 +00:00
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 ;
2012-02-27 12:23:15 +00:00
}
}
2017-01-13 00:39:50 +00:00
static void Fragment_ClipTriangle ( fragmentdecal_t * dec , float * a , float * b , float * c )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
//emit the triangle, and clip it's fragments.
int start , i ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
int p ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
if ( dec - > numtris = = MAXFRAGMENTTRIS )
return ; //:(
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
start = dec - > numtris ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
VectorCopy ( a , decalfragmentverts [ dec - > numtris * 3 + 0 ] ) ;
VectorCopy ( b , decalfragmentverts [ dec - > numtris * 3 + 1 ] ) ;
VectorCopy ( c , decalfragmentverts [ dec - > numtris * 3 + 2 ] ) ;
dec - > numtris + + ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
//clip all the fragments to all of the planes.
//This will produce a quad if the source triangle was big enough.
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
for ( p = 0 ; p < 6 ; p + + )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
for ( i = start ; i < dec - > numtris ; i + + )
Fragment_ClipTriToPlane ( i , dec - > planenorm [ p ] , dec - > plantdist [ p ] , dec ) ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
}
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
# else
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
void Fragment_ClipPoly ( fragmentdecal_t * dec , int numverts , float * inverts , shader_t * surfshader )
{
//emit the triangle, and clip it's fragments.
int p ;
float verts [ MAXFRAGMENTVERTS * C ] ;
float verts2 [ MAXFRAGMENTVERTS * C ] ;
float * cverts ;
int flip ;
vec3_t d1 , d2 , n ;
size_t numtris ;
if ( numverts > MAXFRAGMENTTRIS )
return ;
if ( r_decal_noperpendicular . ival )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
VectorSubtract ( inverts + C * 1 , inverts + C * 0 , d1 ) ;
for ( p = 2 ; ; p + + )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
if ( p > = numverts )
return ;
VectorSubtract ( inverts + C * p , inverts + C * 0 , d2 ) ;
CrossProduct ( d1 , d2 , n ) ;
if ( DotProduct ( n , n ) > .1 )
break ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
VectorNormalizeFast ( n ) ;
if ( DotProduct ( n , dec - > normal ) < 0.1 )
return ; //faces too far way from the normal
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +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 ] ) ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
//clip the triangle to the 6 planes.
flip = 0 ;
for ( p = 1 ; p < dec - > numplanes ; p + + )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +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 ] ) ;
if ( numverts < 3 ) //totally clipped.
return ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
if ( flip )
cverts = verts2 ;
2012-02-27 12:23:15 +00:00
else
2017-01-13 00:39:50 +00:00
cverts = verts ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
//decompose the resultant polygon into triangles.
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
numtris = 0 ;
while ( numverts - - > 2 )
{
if ( numtris = = MAXFRAGMENTTRIS )
{
dec - > callback ( dec - > ctx , decalfragmentverts , numtris , NULL ) ;
numtris = 0 ;
break ;
}
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
VectorCopy ( ( cverts + C * 0 ) , decalfragmentverts [ numtris * 3 + 0 ] ) ;
VectorCopy ( ( cverts + C * ( numverts - 1 ) ) , decalfragmentverts [ numtris * 3 + 1 ] ) ;
VectorCopy ( ( cverts + C * numverts ) , decalfragmentverts [ numtris * 3 + 2 ] ) ;
numtris + + ;
}
if ( numtris )
dec - > callback ( dec - > ctx , decalfragmentverts , numtris , surfshader ) ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
# endif
//this could be inlined, but I'm lazy.
static void Fragment_Mesh ( fragmentdecal_t * dec , mesh_t * mesh , mtexinfo_t * texinfo )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
int i ;
vecV_t verts [ 3 ] ;
shader_t * surfshader = texinfo - > texture - > shader ;
2015-03-05 22:14:21 +00:00
2018-01-14 05:32:20 +00:00
if ( ( surfshader - > flags & SHADER_NOMARKS ) | | ! mesh )
2017-01-13 00:39:50 +00:00
return ;
2015-03-05 22:14:21 +00:00
2017-01-13 00:39:50 +00:00
if ( dec - > surfflagmask )
{
if ( ( texinfo - > flags & dec - > surfflagmask ) ! = dec - > surfflagmatch )
return ;
2004-08-21 01:25:48 +00:00
}
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
/*if its a triangle fan/poly/quad then we can just submit the entire thing without generating extra fragments*/
if ( mesh - > istrifan )
2010-08-28 17:14:38 +00:00
{
2017-01-13 00:39:50 +00:00
Fragment_ClipPoly ( dec , mesh - > numvertexes , mesh - > xyz_array [ 0 ] , surfshader ) ;
return ;
2010-08-28 17:14:38 +00:00
}
2017-01-13 00:39:50 +00:00
//Fixme: optimise q3 patches (quad strips with bends between each strip)
/*otherwise it goes in and out in weird places*/
for ( i = 0 ; i < mesh - > numindexes ; i + = 3 )
2012-05-09 15:30:53 +00:00
{
2017-01-13 00:39:50 +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 ] , surfshader ) ;
2012-05-09 15:30:53 +00:00
}
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
# ifdef Q1BSPS
static void Q1BSP_ClipDecalToNodes ( model_t * mod , fragmentdecal_t * dec , mnode_t * node )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
mplane_t * splitplane ;
float dist ;
msurface_t * surf ;
int i ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
if ( node - > contents < 0 )
return ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
splitplane = node - > plane ;
dist = DotProduct ( dec - > center , splitplane - > normal ) - splitplane - > dist ;
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
if ( dist > dec - > radius )
{
Q1BSP_ClipDecalToNodes ( mod , dec , node - > children [ 0 ] ) ;
return ;
}
if ( dist < - dec - > radius )
{
Q1BSP_ClipDecalToNodes ( mod , dec , node - > children [ 1 ] ) ;
2012-02-27 12:23:15 +00:00
return ;
2017-01-13 00:39:50 +00:00
}
2012-02-27 12:23:15 +00:00
2017-01-13 00:39:50 +00:00
// mark the polygons
surf = mod - > surfaces + node - > firstsurface ;
if ( r_decal_noperpendicular . ival )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < node - > numsurfaces ; i + + , surf + + )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
if ( surf - > flags & SURF_PLANEBACK )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
if ( - DotProduct ( surf - > plane - > normal , dec - > normal ) > - 0.5 )
continue ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
else
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
if ( DotProduct ( surf - > plane - > normal , dec - > normal ) > - 0.5 )
continue ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
Fragment_Mesh ( dec , surf - > mesh , surf - > texinfo ) ;
2012-02-27 12:23:15 +00:00
}
}
2014-06-21 17:58:17 +00:00
else
{
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < node - > numsurfaces ; i + + , surf + + )
Fragment_Mesh ( dec , surf - > mesh , surf - > texinfo ) ;
2014-06-21 17:58:17 +00:00
}
2017-01-13 00:39:50 +00:00
Q1BSP_ClipDecalToNodes ( mod , dec , node - > children [ 0 ] ) ;
Q1BSP_ClipDecalToNodes ( mod , dec , node - > children [ 1 ] ) ;
2014-06-21 17:58:17 +00:00
}
2017-01-13 00:39:50 +00:00
# endif
# ifdef RTLIGHTS
extern int sh_shadowframe ;
# else
static int sh_shadowframe ;
# endif
# ifdef Q3BSPS
static void Q3BSP_ClipDecalToNodes ( fragmentdecal_t * dec , mnode_t * node )
2005-07-16 00:53:08 +00:00
{
2017-01-13 00:39:50 +00:00
mplane_t * splitplane ;
float dist ;
msurface_t * * msurf ;
msurface_t * surf ;
mleaf_t * leaf ;
int i ;
2005-07-16 00:53:08 +00:00
2017-01-13 00:39:50 +00:00
if ( node - > contents ! = - 1 )
2012-02-27 12:23:15 +00:00
{
2017-01-13 00:39:50 +00:00
leaf = ( mleaf_t * ) node ;
// mark the polygons
msurf = leaf - > firstmarksurface ;
for ( i = 0 ; i < leaf - > nummarksurfaces ; i + + , msurf + + )
2015-03-05 22:14:21 +00:00
{
2017-01-13 00:39:50 +00:00
surf = * msurf ;
2015-03-05 22:14:21 +00:00
2022-04-23 20:10:18 +00:00
# ifdef RTLIGHTS
2017-01-13 00:39:50 +00:00
//only check each surface once. it can appear in multiple leafs.
if ( surf - > shadowframe = = sh_shadowframe )
continue ;
surf - > shadowframe = sh_shadowframe ;
2022-04-23 20:10:18 +00:00
# endif
2017-01-13 00:39:50 +00:00
Fragment_Mesh ( dec , surf - > mesh , surf - > texinfo ) ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
return ;
2012-02-27 12:23:15 +00:00
}
2017-01-13 00:39:50 +00:00
splitplane = node - > plane ;
dist = DotProduct ( dec - > center , splitplane - > normal ) - splitplane - > dist ;
2014-04-13 04:23:13 +00:00
2017-01-13 00:39:50 +00:00
if ( dist > dec - > radius )
2005-07-16 00:53:08 +00:00
{
2017-01-13 00:39:50 +00:00
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
return ;
2005-07-16 00:53:08 +00:00
}
2017-01-13 00:39:50 +00:00
if ( dist < - dec - > radius )
2005-07-16 00:53:08 +00:00
{
2017-01-13 00:39:50 +00:00
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
return ;
}
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 0 ] ) ;
Q3BSP_ClipDecalToNodes ( dec , node - > children [ 1 ] ) ;
}
# endif
2011-05-19 13:34:07 +00:00
2017-01-13 00:39:50 +00:00
void Mod_ClipDecal ( struct model_s * mod , vec3_t center , vec3_t normal , vec3_t tangent1 , vec3_t tangent2 , float size , unsigned int surfflagmask , unsigned int surfflagmatch , void ( * callback ) ( void * ctx , vec3_t * fte_restrict points , size_t numpoints , shader_t * shader ) , void * ctx )
{ //quad marks a full, independant quad
int p ;
float r ;
fragmentdecal_t dec ;
VectorCopy ( center , dec . center ) ;
VectorCopy ( normal , dec . normal ) ;
dec . radius = 0 ;
dec . callback = callback ;
dec . ctx = ctx ;
dec . surfflagmask = surfflagmask ;
dec . surfflagmatch = surfflagmatch ;
VectorCopy ( tangent1 , dec . planenorm [ 0 ] ) ;
VectorNegate ( tangent1 , dec . planenorm [ 1 ] ) ;
VectorCopy ( tangent2 , dec . planenorm [ 2 ] ) ;
VectorNegate ( tangent2 , dec . planenorm [ 3 ] ) ;
VectorCopy ( dec . normal , dec . planenorm [ 4 ] ) ;
VectorNegate ( dec . normal , dec . planenorm [ 5 ] ) ;
for ( p = 0 ; p < 6 ; p + + )
{
r = sqrt ( DotProduct ( dec . planenorm [ p ] , dec . planenorm [ p ] ) ) ;
VectorScale ( dec . planenorm [ p ] , 1 / r , dec . planenorm [ p ] ) ;
r * = size / 2 ;
if ( r > dec . radius )
dec . radius = r ;
dec . planedist [ p ] = - ( r - DotProduct ( dec . center , dec . planenorm [ p ] ) ) ;
2005-07-16 00:53:08 +00:00
}
2017-01-13 00:39:50 +00:00
dec . numplanes = 6 ;
2005-07-16 00:53:08 +00:00
2017-01-13 00:39:50 +00:00
sh_shadowframe + + ;
2020-10-23 02:50:11 +00:00
if ( ! mod | | mod - > loadstate ! = MLS_LOADED )
return ;
2020-10-26 06:30:35 +00:00
else if ( mod - > type ! = mod_brush )
;
2017-01-13 00:39:50 +00:00
# ifdef Q1BSPS
2017-01-15 13:13:09 +00:00
else if ( mod - > fromgame = = fg_quake | | mod - > fromgame = = fg_halflife )
2017-01-13 00:39:50 +00:00
Q1BSP_ClipDecalToNodes ( mod , & dec , mod - > rootnode ) ;
# endif
# ifdef Q3BSPS
2020-09-29 07:09:01 +00:00
else if ( mod - > fromgame = = fg_quake3 )
2018-10-23 07:09:06 +00:00
{
if ( mod - > submodelof )
{
msurface_t * surf ;
for ( surf = mod - > surfaces + mod - > firstmodelsurface , p = 0 ; p < mod - > nummodelsurfaces ; p + + , surf + + )
Fragment_Mesh ( & dec , surf - > mesh , surf - > texinfo ) ;
}
else
Q3BSP_ClipDecalToNodes ( & dec , mod - > rootnode ) ;
}
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
2017-01-13 00:39:50 +00:00
# ifdef TERRAIN
2020-09-29 07:09:01 +00:00
if ( mod - > terrain )
2017-01-13 00:39:50 +00:00
Terrain_ClipDecal ( & dec , center , dec . radius , mod ) ;
# endif
2005-07-16 00:53:08 +00:00
}
2017-01-13 00:39:50 +00:00
# endif
2005-07-16 00:53:08 +00:00
2004-08-21 01:25:48 +00:00
/*
2017-01-13 00:39:50 +00:00
Decal functions
2004-08-21 01:25:48 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2017-01-13 00:39:50 +00:00
Physics functions ( common )
2015-01-07 13:56:16 +00:00
*/
2017-01-13 00:39:50 +00:00
# ifdef Q1BSPS
2015-01-07 13:56:16 +00:00
2017-01-13 00:39:50 +00:00
void Q1BSP_CheckHullNodes ( hull_t * hull )
2015-01-07 13:56:16 +00:00
{
2017-01-13 00:39:50 +00:00
int num , c ;
mclipnode_t * node ;
for ( num = hull - > firstclipnode ; num < hull - > lastclipnode ; num + + )
2015-01-07 13:56:16 +00:00
{
2017-01-13 00:39:50 +00:00
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 " ) ;
2015-01-07 13:56:16 +00:00
}
2017-01-13 00:39:50 +00:00
}
2015-01-07 13:56:16 +00:00
2019-07-02 04:12:20 +00:00
static int Q1_ModelPointContents ( mnode_t * node , const vec3_t p )
2017-01-13 00:39:50 +00:00
{
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 ] ;
2015-01-07 13:56:16 +00:00
}
2017-01-13 00:39:50 +00:00
return node - > contents ;
2015-01-07 13:56:16 +00:00
}
2017-01-13 00:39:50 +00:00
# endif //Q1BSPS
/*
= = = = = = = = = = = = = = = = = =
SV_HullPointContents
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
= = = = = = = = = = = = = = = = = =
*/
2019-07-02 04:12:20 +00:00
static int Q1_HullPointContents ( hull_t * hull , int num , const vec3_t p )
2017-01-13 00:39:50 +00:00
{
float d ;
mclipnode_t * node ;
mplane_t * plane ;
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
while ( num > = 0 )
{
node = hull - > clipnodes + num ;
plane = hull - > planes + node - > planenum ;
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +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 ] ;
}
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
return num ;
}
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
# define DIST_EPSILON (0.03125)
# if 1
2019-01-13 16:51:50 +00:00
2019-01-13 17:56:26 +00:00
static const unsigned int q1toftecontents [ ] =
2019-01-13 16:51:50 +00:00
{
0 , //EMPTY
FTECONTENTS_SOLID , //SOLID
FTECONTENTS_WATER , //WATER
FTECONTENTS_SLIME , //SLIME
FTECONTENTS_LAVA , //LAVA
FTECONTENTS_SKY , //SKY
FTECONTENTS_SOLID , //STRIPPED
FTECONTENTS_PLAYERCLIP , //CLIP
Q2CONTENTS_CURRENT_0 , //FLOW_1
Q2CONTENTS_CURRENT_90 , //FLOW_2
Q2CONTENTS_CURRENT_180 , //FLOW_3
Q2CONTENTS_CURRENT_270 , //FLOW_4
Q2CONTENTS_CURRENT_UP , //FLOW_5
Q2CONTENTS_CURRENT_DOWN , //FLOW_6
Q2CONTENTS_WINDOW , //TRANS
FTECONTENTS_LADDER , //LADDER
} ;
2017-01-13 00:39:50 +00:00
enum
{
rht_solid ,
rht_empty ,
rht_impact
} ;
struct rhtctx_s
{
2019-01-13 16:51:50 +00:00
unsigned int checkcontents ;
2017-01-13 00:39:50 +00:00
vec3_t start , end ;
mclipnode_t * clipnodes ;
mplane_t * planes ;
} ;
2019-07-02 04:12:20 +00:00
static int Q1BSP_RecursiveHullTrace ( struct rhtctx_s * ctx , int num , float p1f , float p2f , const vec3_t p1 , const vec3_t p2 , trace_t * trace )
2017-01-13 00:39:50 +00:00
{
mclipnode_t * node ;
mplane_t * plane ;
float t1 , t2 ;
vec3_t mid ;
int side ;
float midf ;
int rht ;
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
reenter :
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
if ( num < 0 )
2016-07-12 00:40:13 +00:00
{
2019-01-13 16:51:50 +00:00
unsigned int c = q1toftecontents [ - 1 - num ] ;
2017-01-13 00:39:50 +00:00
/*hit a leaf*/
2019-01-13 16:51:50 +00:00
if ( c & ctx - > checkcontents )
2016-07-12 00:40:13 +00:00
{
2019-01-13 16:51:50 +00:00
trace - > contents = c ;
2017-01-13 00:39:50 +00:00
if ( trace - > allsolid )
trace - > startsolid = true ;
return rht_solid ;
2016-07-12 00:40:13 +00:00
}
2017-01-13 00:39:50 +00:00
else
2016-07-12 00:40:13 +00:00
{
2017-01-13 00:39:50 +00:00
trace - > allsolid = false ;
2019-01-13 16:51:50 +00:00
if ( c & FTECONTENTS_FLUID )
2017-01-13 00:39:50 +00:00
trace - > inwater = true ;
2019-01-13 16:51:50 +00:00
else
trace - > inopen = true ;
2017-01-13 00:39:50 +00:00
return rht_empty ;
2016-07-12 00:40:13 +00:00
}
}
2017-01-13 00:39:50 +00:00
/*its a node*/
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
/*get the node info*/
node = ctx - > clipnodes + num ;
plane = ctx - > planes + node - > planenum ;
2015-01-07 13:56:16 +00:00
2017-01-13 00:39:50 +00:00
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 ;
}
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +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 ;
}
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
if ( plane - > type < 3 )
{
t1 = ctx - > start [ plane - > type ] - plane - > dist ;
t2 = ctx - > end [ plane - > type ] - plane - > dist ;
}
else
{
t1 = DotProduct ( plane - > normal , ctx - > start ) - plane - > dist ;
t2 = DotProduct ( plane - > normal , ctx - > end ) - plane - > dist ;
}
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
side = t1 < 0 ;
2009-07-14 15:13:12 +00:00
2017-01-13 00:39:50 +00:00
midf = t1 / ( t1 - t2 ) ;
if ( midf < p1f ) midf = p1f ;
if ( midf > p2f ) midf = p2f ;
VectorInterpolate ( ctx - > start , midf , ctx - > end , mid ) ;
2004-08-21 01:25:48 +00:00
2019-01-13 16:51:50 +00:00
//check the near side
2017-01-13 00:39:50 +00:00
rht = Q1BSP_RecursiveHullTrace ( ctx , node - > children [ side ] , p1f , midf , p1 , mid , trace ) ;
if ( rht ! = rht_empty & & ! trace - > allsolid )
return rht ;
2019-01-13 16:51:50 +00:00
//check the far side
2017-01-13 00:39:50 +00:00
rht = Q1BSP_RecursiveHullTrace ( ctx , node - > children [ side ^ 1 ] , midf , p2f , mid , p2 , trace ) ;
if ( rht ! = rht_solid )
return rht ;
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
if ( side )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
/*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 ) ;
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
else
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
/*we impacted the front of the node*/
trace - > plane . dist = plane - > dist ;
VectorCopy ( plane - > normal , trace - > plane . normal ) ;
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
2004-08-21 01:25:48 +00:00
}
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
t1 = DotProduct ( trace - > plane . normal , ctx - > start ) - trace - > plane . dist ;
t2 = DotProduct ( trace - > plane . normal , ctx - > end ) - trace - > plane . dist ;
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
2009-07-14 15:13:12 +00:00
2017-01-13 00:39:50 +00:00
midf = bound ( 0 , midf , 1 ) ;
trace - > fraction = midf ;
VectorCopy ( mid , trace - > endpos ) ;
VectorInterpolate ( ctx - > start , midf , ctx - > end , trace - > endpos ) ;
return rht_impact ;
}
2019-07-02 04:12:20 +00:00
qboolean Q1BSP_RecursiveHullCheck ( hull_t * hull , int num , const vec3_t p1 , const vec3_t p2 , unsigned int hitcontents , trace_t * trace )
2017-01-13 00:39:50 +00:00
{
if ( VectorEquals ( p1 , p2 ) )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
/*points cannot cross planes, so do it faster*/
2019-01-13 16:51:50 +00:00
int q1 = Q1_HullPointContents ( hull , num , p1 ) ;
unsigned int c = q1toftecontents [ - 1 - q1 ] ;
trace - > contents = c ;
if ( c & hitcontents )
2017-01-13 00:39:50 +00:00
trace - > startsolid = true ;
2019-01-13 16:51:50 +00:00
else if ( c & FTECONTENTS_FLUID )
{
2017-01-13 00:39:50 +00:00
trace - > allsolid = false ;
trace - > inwater = true ;
2019-01-13 16:51:50 +00:00
}
else
{
trace - > allsolid = false ;
trace - > inopen = true ;
2017-01-13 00:39:50 +00:00
}
return true ;
}
else
{
struct rhtctx_s ctx ;
VectorCopy ( p1 , ctx . start ) ;
VectorCopy ( p2 , ctx . end ) ;
ctx . clipnodes = hull - > clipnodes ;
ctx . planes = hull - > planes ;
2019-01-13 16:51:50 +00:00
ctx . checkcontents = hitcontents ;
return Q1BSP_RecursiveHullTrace ( & ctx , num , 0 , 1 , p1 , p2 , trace ) ! = rht_impact ;
2017-01-13 00:39:50 +00:00
}
}
2009-07-14 15:13:12 +00:00
2017-01-13 00:39:50 +00:00
# else
qboolean Q1BSP_RecursiveHullCheck ( hull_t * hull , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
{
mclipnode_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 )
2004-08-21 01:25:48 +00:00
{
2017-01-13 00:39:50 +00:00
trace - > allsolid = false ;
if ( num = = Q1CONTENTS_EMPTY )
trace - > inopen = true ;
2009-07-14 15:13:12 +00:00
else
2017-01-13 00:39:50 +00:00
trace - > inwater = true ;
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
else
trace - > startsolid = true ;
return true ; // empty
2004-08-21 01:25:48 +00:00
}
2017-01-13 00:39:50 +00:00
//
// find the point distances
//
node = hull - > clipnodes + num ;
plane = hull - > planes + node - > planenum ;
2004-08-21 01:25:48 +00:00
2017-01-13 00:39:50 +00:00
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 ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +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
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
// 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 ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
midf = p1f + ( p2f - p1f ) * frac ;
for ( i = 0 ; i < 3 ; i + + )
mid [ i ] = p1 [ i ] + frac * ( p2 [ i ] - p1 [ i ] ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
side = ( t1 < 0 ) ;
2015-03-03 00:14:43 +00:00
2017-01-13 00:39:50 +00:00
// move up to the node
if ( ! Q1BSP_RecursiveHullCheck ( hull , node - > children [ side ] , p1f , midf , p1 , mid , trace ) )
return false ;
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
# ifdef PARANOID
if ( Q1BSP_RecursiveHullCheck ( sv_hullmodel , mid , node - > children [ side ] )
= = Q1CONTENTS_SOLID )
{
Con_Printf ( " mid PointInHullSolid \n " ) ;
return false ;
}
# endif
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +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 ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
if ( trace - > allsolid )
return false ; // never got out of the solid area
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
//==================
// the other side of the node is solid, this is the impact point
//==================
if ( ! side )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
VectorCopy ( plane - > normal , trace - > plane . normal ) ;
trace - > plane . dist = plane - > dist ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
else
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
VectorNegate ( plane - > normal , trace - > plane . normal ) ;
trace - > plane . dist = - plane - > dist ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
while ( Q1_HullPointContents ( hull , hull - > firstclipnode , mid )
= = Q1CONTENTS_SOLID )
{ // shouldn't really happen, but does occasionally
if ( ! ( frac < 10000000 ) & & ! ( frac > - 10000000 ) )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
trace - > fraction = 0 ;
VectorClear ( trace - > endpos ) ;
Con_Printf ( " nan in traceline \n " ) ;
return false ;
}
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 ] ) ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
trace - > fraction = midf ;
VectorCopy ( mid , trace - > endpos ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
return false ;
}
# endif
2005-05-13 10:42:48 +00:00
2021-04-14 05:21:04 +00:00
#if 0 //def Q1BSPS
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +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 ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
qboolean capsule ;
float radius ;
/*set even for sphere traces (used for bbox tests)*/
vec3_t mins ;
vec3_t maxs ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
vec3_t start ;
vec3_t end ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
vec3_t up ;
vec3_t capsulesize ;
vec3_t extents ;
} ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +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 ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
for ( ; brush ; brush = brush - > next )
{
/*ignore if its not solid to us*/
if ( ! ( traceinfo - > solidcontents & brush - > contents ) )
continue ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
startout = false ;
endout = false ;
enterplane = NULL ;
enterfrac = - 1 ;
exitfrac = 10 ;
for ( i = brush - > numplanes , plane = brush - > planes ; i ; i - - , plane + + )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
/*calculate the distance based upon the shape of the object we're tracing for*/
if ( traceinfo - > capsule )
{
dist = DotProduct ( traceinfo - > up , plane - > normal ) ;
dist = dist * ( traceinfo - > capsulesize [ ( dist < 0 ) ? 1 : 2 ] ) - traceinfo - > capsulesize [ 0 ] ;
dist = plane - > dist - dist ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
//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 ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
d1 = DotProduct ( traceinfo - > start , plane - > normal ) - dist ;
d2 = DotProduct ( traceinfo - > end , plane - > normal ) - dist ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
if ( d1 > = 0 )
startout = true ;
if ( d2 > 0 )
endout = true ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
//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 ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
//if we're fully inside the plane, then whatever is happening is not relevent for this plane
if ( d1 < 0 & & d2 < = 0 )
continue ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
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 )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
enterfrac = f ;
enterplane = plane ;
enterdist = dist ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
}
else
{
//left the brush, favour the nearest plane (smallest frac)
if ( exitfrac > f )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
exitfrac = f ;
2005-05-13 10:42:48 +00:00
}
}
}
2017-01-13 00:39:50 +00:00
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 nearp , farp ;
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 ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
if ( node - > plane - > normal [ i ] > 0 )
{
nearp [ i ] = bmins [ i ] ;
farp [ i ] = bmaxs [ i ] ;
}
else
{
nearp [ i ] = bmaxs [ i ] ;
farp [ i ] = bmins [ i ] ;
}
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
nd = DotProduct ( node - > plane - > normal , nearp ) - node - > plane - > dist ;
fd = DotProduct ( node - > plane - > normal , farp ) - node - > plane - > dist ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
/*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 ;
}
}
}
2019-07-02 04:12:20 +00:00
static void Q1BSP_RecursiveBrushCheck ( struct traceinfo_s * traceinfo , mnode_t * node , float p1f , float p2f , const vec3_t p1 , const vec3_t p2 )
2017-01-13 00:39:50 +00:00
{
mplane_t * plane ;
float t1 , t2 ;
float frac ;
int i ;
vec3_t mid ;
int side ;
float midf ;
float offset ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
if ( node - > brushes )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
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 = = t2 )
{
side = 0 ;
frac = 0 ;
}
else if ( t1 < 0 )
{
frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 ) ;
side = 1 ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
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 ) ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
# endif //Q1BSPS
2005-05-13 10:42:48 +00:00
2021-04-14 05:21:04 +00:00
static unsigned int Q1BSP_TranslateContents ( enum q1contents_e contents )
2017-01-13 00:39:50 +00:00
{
2021-04-14 05:21:04 +00:00
safeswitch ( contents )
{
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 | FTECONTENTS_PLAYERCLIP | FTECONTENTS_MONSTERCLIP ;
case Q1CONTENTS_LADDER : return FTECONTENTS_LADDER ;
case Q1CONTENTS_CLIP : return FTECONTENTS_PLAYERCLIP | FTECONTENTS_MONSTERCLIP ;
case Q1CONTENTS_CURRENT_0 : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_0 ; //q2 is better than nothing, right?
case Q1CONTENTS_CURRENT_90 : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_90 ;
case Q1CONTENTS_CURRENT_180 : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_180 ;
case Q1CONTENTS_CURRENT_270 : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_270 ;
case Q1CONTENTS_CURRENT_UP : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_UP ;
case Q1CONTENTS_CURRENT_DOWN : return FTECONTENTS_WATER | Q2CONTENTS_CURRENT_DOWN ;
case Q1CONTENTS_TRANS : return FTECONTENTS_SOLID ;
case Q1CONTENTS_MONSTERCLIP : return FTECONTENTS_MONSTERCLIP ;
case Q1CONTENTS_PLAYERCLIP : return FTECONTENTS_PLAYERCLIP ;
2021-07-06 00:12:12 +00:00
case Q1CONTENTS_CORPSE : return FTECONTENTS_CORPSE ;
2021-04-14 05:21:04 +00:00
safedefault :
2017-01-13 00:39:50 +00:00
Con_Printf ( " Q1BSP_TranslateContents: Unknown contents type - %i " , contents ) ;
return FTECONTENTS_SOLID ;
}
}
2019-07-02 04:12:20 +00:00
int Q1BSP_HullPointContents ( hull_t * hull , const vec3_t p )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
return Q1BSP_TranslateContents ( Q1_HullPointContents ( hull , hull - > firstclipnode , p ) ) ;
}
# ifdef Q1BSPS
2019-07-02 04:12:20 +00:00
unsigned int Q1BSP_PointContents ( model_t * model , const vec3_t axis [ 3 ] , const vec3_t point )
2017-01-13 00:39:50 +00:00
{
int contents ;
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_PointContents ( model , NULL , transformed ) ;
}
else
{
if ( ! model - > firstmodelsurface )
{
contents = Q1BSP_TranslateContents ( Q1_ModelPointContents ( model - > nodes , point ) ) ;
}
else
contents = Q1BSP_HullPointContents ( & model - > hulls [ 0 ] , point ) ;
}
# ifdef TERRAIN
if ( model - > terrain )
contents | = Heightmap_PointContents ( model , NULL , point ) ;
# endif
return contents ;
}
2018-07-24 13:59:42 +00:00
void Q1BSP_LoadBrushes ( model_t * model , bspx_header_t * bspx , void * mod_base )
2017-01-13 00:39:50 +00:00
{
2021-04-14 05:21:04 +00:00
const struct {
2017-01-13 00:39:50 +00:00
unsigned int ver ;
unsigned int modelnum ;
unsigned int numbrushes ;
unsigned int numplanes ;
2021-04-14 05:21:04 +00:00
} * srcmodel ;
const struct {
2017-01-13 00:39:50 +00:00
float mins [ 3 ] ;
float maxs [ 3 ] ;
signed short contents ;
unsigned short numplanes ;
2021-04-14 05:21:04 +00:00
} * srcbrush ;
2017-01-13 00:39:50 +00:00
/*
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 . . .
*/
2021-04-14 05:21:04 +00:00
const struct {
2017-01-13 00:39:50 +00:00
vec3_t normal ;
float dist ;
2021-04-14 05:21:04 +00:00
} * srcplane ;
2017-01-13 00:39:50 +00:00
static vec3_t axis [ 3 ] = { { 1 , 0 , 0 } , { 0 , 1 , 0 } , { 0 , 0 , 1 } } ;
2021-04-14 05:21:04 +00:00
unsigned int br , pl ;
q2cbrush_t * brush ;
q2cbrushside_t * sides ; //grr!
mplane_t * planes ; //bulky?
2017-01-13 00:39:50 +00:00
unsigned int lumpsizeremaining ;
2021-04-14 05:21:04 +00:00
unsigned int numplanes ;
2005-05-13 10:42:48 +00:00
2021-04-14 05:21:04 +00:00
unsigned int srcver , srcmodelidx , modbrushes , modplanes ;
2017-01-13 00:39:50 +00:00
2021-04-14 05:21:04 +00:00
srcmodel = BSPX_FindLump ( bspx , mod_base , " BRUSHLIST " , & lumpsizeremaining ) ;
if ( ! srcmodel )
2009-10-06 00:33:54 +00:00
return ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
while ( lumpsizeremaining )
2016-07-12 00:40:13 +00:00
{
2021-04-14 05:21:04 +00:00
if ( lumpsizeremaining < sizeof ( * srcmodel ) )
2017-01-13 00:39:50 +00:00
return ;
2021-04-14 05:21:04 +00:00
srcver = LittleLong ( srcmodel - > ver ) ;
srcmodelidx = LittleLong ( srcmodel - > modelnum ) ;
modbrushes = LittleLong ( srcmodel - > numbrushes ) ;
modplanes = LittleLong ( srcmodel - > numplanes ) ;
if ( srcver ! = 1 | | lumpsizeremaining < sizeof ( * srcmodel ) + modbrushes * sizeof ( * srcmodel ) + modplanes * sizeof ( * srcplane ) )
2017-01-13 00:39:50 +00:00
return ;
2021-04-14 05:21:04 +00:00
lumpsizeremaining - = ( ( const char * ) ( srcmodel + 1 ) + modbrushes * sizeof ( * srcbrush ) + modplanes * sizeof ( * srcplane ) ) - ( const char * ) srcmodel ;
2017-01-13 00:39:50 +00:00
2021-04-14 05:21:04 +00:00
if ( srcmodelidx > model - > numsubmodels )
2017-01-13 00:39:50 +00:00
return ;
2021-04-14 05:21:04 +00:00
brush = ZG_Malloc ( & model - > memgroup , sizeof ( * brush ) * modbrushes +
sizeof ( * sides ) * ( modbrushes * 6 + modplanes ) +
sizeof ( * planes ) * ( modbrushes * 6 + modplanes ) ) ;
sides = ( void * ) ( brush + modbrushes ) ;
planes = ( void * ) ( sides + modbrushes * 6 + modplanes ) ;
model - > submodels [ srcmodelidx ] . brushes = brush ;
srcbrush = ( const void * ) ( srcmodel + 1 ) ;
for ( br = 0 ; br < modbrushes ; br + + , srcbrush = ( const void * ) srcplane )
2016-07-12 00:40:13 +00:00
{
2017-01-13 00:39:50 +00:00
/*byteswap it all in place*/
2021-04-14 05:21:04 +00:00
brush - > absmins [ 0 ] = LittleFloat ( srcbrush - > mins [ 0 ] ) ;
brush - > absmins [ 1 ] = LittleFloat ( srcbrush - > mins [ 1 ] ) ;
brush - > absmins [ 2 ] = LittleFloat ( srcbrush - > mins [ 2 ] ) ;
brush - > absmaxs [ 0 ] = LittleFloat ( srcbrush - > maxs [ 0 ] ) ;
brush - > absmaxs [ 1 ] = LittleFloat ( srcbrush - > maxs [ 1 ] ) ;
brush - > absmaxs [ 2 ] = LittleFloat ( srcbrush - > maxs [ 2 ] ) ;
numplanes = ( unsigned short ) LittleShort ( srcbrush - > numplanes ) ;
2017-01-13 00:39:50 +00:00
/*make sure planes don't overflow*/
2021-04-14 05:21:04 +00:00
if ( numplanes > modplanes )
2016-07-12 00:40:13 +00:00
return ;
2021-04-14 05:21:04 +00:00
modplanes - = numplanes ;
2014-12-02 02:00:41 +00:00
2017-01-13 00:39:50 +00:00
/*set up the mbrush from the file*/
2021-04-14 05:21:04 +00:00
brush - > contents = Q1BSP_TranslateContents ( LittleShort ( srcbrush - > contents ) ) ;
brush - > brushside = sides ;
for ( srcplane = ( const void * ) ( srcbrush + 1 ) ; numplanes - - > 0 ; srcplane + + )
2017-01-13 00:39:50 +00:00
{
2021-04-14 05:21:04 +00:00
planes - > normal [ 0 ] = LittleFloat ( srcplane - > normal [ 0 ] ) ;
planes - > normal [ 1 ] = LittleFloat ( srcplane - > normal [ 1 ] ) ;
planes - > normal [ 2 ] = LittleFloat ( srcplane - > normal [ 2 ] ) ;
planes - > dist = LittleFloat ( srcplane - > dist ) ;
2021-07-04 03:58:24 +00:00
CategorizePlane ( planes ) ;
2021-04-14 05:21:04 +00:00
sides - > surface = NULL ;
sides + + - > plane = planes + + ;
2017-01-13 00:39:50 +00:00
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
/*and add axial planes acording to the brush's bbox*/
for ( pl = 0 ; pl < 3 ; pl + + )
{
2021-04-14 05:21:04 +00:00
VectorCopy ( axis [ pl ] , planes - > normal ) ;
planes - > dist = brush - > absmaxs [ pl ] ;
2021-07-17 15:11:41 +00:00
CategorizePlane ( planes ) ;
2021-04-14 05:21:04 +00:00
sides - > surface = NULL ;
sides + + - > plane = planes + + ;
2017-01-13 00:39:50 +00:00
}
for ( pl = 0 ; pl < 3 ; pl + + )
{
2021-04-14 05:21:04 +00:00
VectorNegate ( axis [ pl ] , planes - > normal ) ;
planes - > dist = - brush - > absmins [ pl ] ;
2021-10-05 06:30:54 +00:00
CategorizePlane ( planes ) ;
2020-10-26 06:30:35 +00:00
2021-04-14 05:21:04 +00:00
sides - > surface = NULL ;
sides + + - > plane = planes + + ;
}
brush - > numsides = sides - brush - > brushside ;
brush + + ;
2017-01-13 00:39:50 +00:00
}
2021-04-14 05:21:04 +00:00
model - > submodels [ srcmodelidx ] . numbrushes = brush - model - > submodels [ srcmodelidx ] . brushes ;
2017-01-13 00:39:50 +00:00
/*move on to the next model*/
2021-04-14 05:21:04 +00:00
srcmodel = ( const void * ) srcbrush ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
}
2005-05-13 10:42:48 +00:00
2019-07-02 04:12:20 +00:00
hull_t * Q1BSP_ChooseHull ( model_t * model , int forcehullnum , const vec3_t mins , const vec3_t maxs , vec3_t offset )
2017-01-13 00:39:50 +00:00
{
hull_t * hull ;
vec3_t size ;
VectorSubtract ( maxs , mins , size ) ;
if ( forcehullnum > = 1 & & forcehullnum < = MAX_MAP_HULLSM & & model - > hulls [ forcehullnum - 1 ] . available )
hull = & model - > hulls [ forcehullnum - 1 ] ;
2005-09-08 22:52:46 +00:00
else
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
# ifdef HEXEN2
if ( model - > hulls [ 5 ] . available )
{ //choose based on hexen2 sizes.
if ( size [ 0 ] < 3 ) // Point
hull = & model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 8.1 & & model - > hulls [ 4 ] . available )
hull = & model - > hulls [ 4 ] ; //Pentacles
else if ( size [ 0 ] < = 32.1 & & size [ 2 ] < = 28.1 ) // Half Player
hull = & model - > hulls [ 3 ] ;
else if ( size [ 0 ] < = 32.1 ) // Full Player
hull = & model - > hulls [ 1 ] ;
else // Golumn
hull = & model - > hulls [ 5 ] ;
}
else
# endif
2015-03-03 00:14:43 +00:00
{
2017-01-13 00:39:50 +00:00
if ( size [ 0 ] < 3 | | ! model - > hulls [ 1 ] . available )
hull = & model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 32.1 | | ! model - > hulls [ 2 ] . available )
{
if ( size [ 2 ] < 54.1 & & model - > hulls [ 3 ] . available )
hull = & model - > hulls [ 3 ] ; // 32x32x36 (half-life's crouch)
else if ( model - > hulls [ 1 ] . available )
hull = & model - > hulls [ 1 ] ;
else
hull = & model - > hulls [ 0 ] ;
}
else
hull = & model - > hulls [ 2 ] ;
2015-03-03 00:14:43 +00:00
}
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
VectorSubtract ( hull - > clip_mins , mins , offset ) ;
return hull ;
}
2019-07-02 04:12:20 +00:00
qboolean Q1BSP_Trace ( model_t * model , int forcehullnum , const framestate_t * framestate , const vec3_t axis [ 3 ] , const vec3_t start , const vec3_t end , const vec3_t mins , const vec3_t maxs , qboolean capsule , unsigned int hitcontentsmask , trace_t * trace )
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
hull_t * hull ;
vec3_t start_l , end_l ;
vec3_t offset ;
2016-07-12 00:40:13 +00:00
2017-01-13 00:39:50 +00:00
memset ( trace , 0 , sizeof ( trace_t ) ) ;
trace - > fraction = 1 ;
trace - > allsolid = true ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
hull = Q1BSP_ChooseHull ( model , forcehullnum , mins , maxs , offset ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
//fix for hexen2 monsters half-walking into walls.
// if (forent.flags & FL_MONSTER)
// {
// offset[0] = 0;
// offset[1] = 0;
// }
2006-03-04 20:43:48 +00:00
2017-01-13 00:39:50 +00:00
if ( axis )
{
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 ] ) ;
2019-01-13 16:51:50 +00:00
Q1BSP_RecursiveHullCheck ( hull , hull - > firstclipnode , start_l , end_l , hitcontentsmask , trace ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
if ( trace - > fraction = = 1 )
{
VectorCopy ( end , trace - > endpos ) ;
}
else
{
vec3_t iaxis [ 3 ] ;
vec3_t norm ;
Matrix3x3_RM_Invert_Simple ( ( void * ) axis , iaxis ) ;
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 ] ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
/*just interpolate it, its easier than inverse matrix rotations*/
VectorInterpolate ( start , trace - > fraction , end , trace - > endpos ) ;
}
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
else
2005-05-13 10:42:48 +00:00
{
2017-01-13 00:39:50 +00:00
VectorSubtract ( start , offset , start_l ) ;
VectorSubtract ( end , offset , end_l ) ;
2019-01-13 16:51:50 +00:00
Q1BSP_RecursiveHullCheck ( hull , hull - > firstclipnode , start_l , end_l , hitcontentsmask , trace ) ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
if ( trace - > fraction = = 1 )
2005-06-04 04:20:20 +00:00
{
2017-01-13 00:39:50 +00:00
VectorCopy ( end , trace - > endpos ) ;
}
else
{
VectorAdd ( trace - > endpos , offset , trace - > endpos ) ;
2005-06-04 04:20:20 +00:00
}
2016-07-12 00:40:13 +00:00
}
2017-01-13 00:39:50 +00:00
# ifdef TERRAIN
if ( model - > terrain & & trace - > fraction )
2016-07-12 00:40:13 +00:00
{
2017-01-13 00:39:50 +00:00
trace_t hmt ;
Heightmap_Trace ( model , forcehullnum , framestate , axis , start , end , mins , maxs , capsule , hitcontentsmask , & hmt ) ;
if ( hmt . fraction < trace - > fraction )
* trace = hmt ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
# endif
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
return trace - > fraction ! = 1 ;
2005-05-13 10:42:48 +00:00
}
2017-01-13 00:39:50 +00:00
/*
Physics functions ( common )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Rendering functions ( Client only )
*/
2021-12-20 10:06:09 +00:00
# ifdef HAVE_CLIENT
2017-01-13 00:39:50 +00:00
extern int r_dlightframecount ;
//goes through the nodes marking the surfaces near the dynamic light as lit.
2020-03-25 21:29:30 +00:00
void Q1BSP_MarkLights ( dlight_t * light , dlightbitmask_t bit , mnode_t * node )
2009-10-06 00:33:54 +00:00
{
mplane_t * splitplane ;
float dist ;
msurface_t * surf ;
int i ;
2017-01-13 00:39:50 +00:00
float l , maxdist ;
int j , s , t ;
vec3_t impact ;
2023-08-01 11:08:51 +00:00
vec4_t * lmvecs ;
float * lmvecscale ;
2009-11-04 21:16:50 +00:00
2017-01-13 00:39:50 +00:00
if ( node - > contents < 0 )
2009-10-06 00:33:54 +00:00
return ;
splitplane = node - > plane ;
2017-01-13 00:39:50 +00:00
if ( splitplane - > type < 3 )
dist = light - > origin [ splitplane - > type ] - splitplane - > dist ;
else
dist = DotProduct ( light - > origin , splitplane - > normal ) - splitplane - > dist ;
2009-10-06 00:33:54 +00:00
2017-01-13 00:39:50 +00:00
if ( dist > light - > radius )
2009-10-06 00:33:54 +00:00
{
2017-01-13 00:39:50 +00:00
Q1BSP_MarkLights ( light , bit , node - > children [ 0 ] ) ;
2009-10-06 00:33:54 +00:00
return ;
}
2017-01-13 00:39:50 +00:00
if ( dist < - light - > radius )
2009-10-06 00:33:54 +00:00
{
2017-01-13 00:39:50 +00:00
Q1BSP_MarkLights ( light , bit , node - > children [ 1 ] ) ;
2009-10-06 00:33:54 +00:00
return ;
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
maxdist = light - > radius * light - > radius ;
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
// mark the polygons
surf = currentmodel - > surfaces + node - > firstsurface ;
for ( i = 0 ; i < node - > numsurfaces ; i + + , surf + + )
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
{
2017-01-13 00:39:50 +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 ;
2009-11-04 21:16:50 +00:00
2023-08-01 11:08:51 +00:00
if ( currentmodel - > facelmvecs )
lmvecs = currentmodel - > facelmvecs [ surf - currentmodel - > surfaces ] . lmvecs , lmvecscale = currentmodel - > facelmvecs [ surf - currentmodel - > surfaces ] . lmvecscale ;
else
lmvecs = surf - > texinfo - > vecs , lmvecscale = surf - > texinfo - > vecscale ;
2017-01-13 00:39:50 +00:00
// clamp center of light to corner and check brightness
2023-08-01 11:08:51 +00:00
l = DotProduct ( impact , lmvecs [ 0 ] ) + lmvecs [ 0 ] [ 3 ] - surf - > texturemins [ 0 ] ;
2017-01-13 00:39:50 +00:00
s = l + 0.5 ; if ( s < 0 ) s = 0 ; else if ( s > surf - > extents [ 0 ] ) s = surf - > extents [ 0 ] ;
2023-08-01 11:08:51 +00:00
s = ( l - s ) * lmvecscale [ 0 ] ; //FIXME
l = DotProduct ( impact , lmvecs [ 1 ] ) + lmvecs [ 1 ] [ 3 ] - surf - > texturemins [ 1 ] ;
2017-01-13 00:39:50 +00:00
t = l + 0.5 ; if ( t < 0 ) t = 0 ; else if ( t > surf - > extents [ 1 ] ) t = surf - > extents [ 1 ] ;
2023-08-01 11:08:51 +00:00
t = ( l - t ) * lmvecscale [ 1 ] ;
2017-01-13 00:39:50 +00:00
// compare to minimum light
if ( ( s * s + t * t + dist * dist ) < maxdist )
{
if ( surf - > dlightframe ! = r_dlightframecount )
{
surf - > dlightbits = bit ;
surf - > dlightframe = r_dlightframecount ;
}
else
surf - > dlightbits | = bit ;
}
2012-08-04 01:35:52 +00:00
}
2005-05-13 10:42:48 +00:00
2017-01-13 00:39:50 +00:00
Q1BSP_MarkLights ( light , bit , node - > children [ 0 ] ) ;
Q1BSP_MarkLights ( light , bit , node - > children [ 1 ] ) ;
2005-05-13 10:42:48 +00:00
}
2021-04-14 05:21:04 +00:00
//combination of R_AddDynamicLights and R_MarkLights
2023-08-01 11:08:51 +00:00
static void Q1BSP_StainNode_r ( model_t * model , mnode_t * node , float * parms )
2021-04-14 05:21:04 +00:00
{
mplane_t * splitplane ;
float dist ;
msurface_t * surf ;
int i ;
if ( node - > contents < 0 )
return ;
splitplane = node - > plane ;
dist = DotProduct ( ( parms + 1 ) , splitplane - > normal ) - splitplane - > dist ;
if ( dist > ( * parms ) )
{
2023-08-01 11:08:51 +00:00
Q1BSP_StainNode_r ( model , node - > children [ 0 ] , parms ) ;
2021-04-14 05:21:04 +00:00
return ;
}
if ( dist < ( - * parms ) )
{
2023-08-01 11:08:51 +00:00
Q1BSP_StainNode_r ( model , node - > children [ 1 ] , parms ) ;
2021-04-14 05:21:04 +00:00
return ;
}
// mark the polygons
2023-08-01 11:08:51 +00:00
surf = model - > surfaces + node - > firstsurface ;
2021-04-14 05:21:04 +00:00
for ( i = 0 ; i < node - > numsurfaces ; i + + , surf + + )
{
if ( surf - > flags & ~ ( SURF_DRAWALPHA | SURF_DONTWARP | SURF_PLANEBACK ) )
continue ;
2023-08-01 11:08:51 +00:00
Surf_StainSurf ( model , surf , parms ) ;
2021-04-14 05:21:04 +00:00
}
2023-08-01 11:08:51 +00:00
Q1BSP_StainNode_r ( model , node - > children [ 0 ] , parms ) ;
Q1BSP_StainNode_r ( model , node - > children [ 1 ] , parms ) ;
}
static void Q1BSP_StainNode ( model_t * model , float * parms )
{
Q1BSP_StainNode_r ( model , model - > rootnode , parms ) ;
2021-04-14 05:21:04 +00:00
}
2021-12-20 10:06:09 +00:00
static qbyte * q1frustumvis ; //temp use
static int q1_visframecount ; //temp use
static int q1_framecount ; //temp use
struct q1bspprv_s
{
int visframecount ;
int framecount ;
int oldviewclusters [ 2 ] ;
} ;
# define BACKFACE_EPSILON 0.01
static void Q1BSP_RecursiveWorldNode ( mnode_t * node , unsigned int clipflags )
{
int c , side , clipped ;
mplane_t * plane , * clipplane ;
msurface_t * surf , * * mark ;
mleaf_t * pleaf ;
double dot ;
start :
if ( node - > contents = = Q1CONTENTS_SOLID )
return ; // solid
if ( node - > visframe ! = q1_visframecount )
return ;
for ( c = 0 , clipplane = r_refdef . frustum ; c < r_refdef . frustum_numworldplanes ; c + + , clipplane + + )
{
if ( ! ( clipflags & ( 1 < < c ) ) )
continue ; // don't need to clip against it
clipped = BOX_ON_PLANE_SIDE ( node - > minmaxs , node - > minmaxs + 3 , clipplane ) ;
if ( clipped = = 2 )
return ;
else if ( clipped = = 1 )
clipflags - = ( 1 < < c ) ; // node is entirely on screen
}
// if a leaf node, draw stuff
if ( node - > contents < 0 )
{
pleaf = ( mleaf_t * ) node ;
c = ( pleaf - cl . worldmodel - > leafs ) - 1 ;
q1frustumvis [ c > > 3 ] | = 1 < < ( c & 7 ) ;
mark = pleaf - > firstmarksurface ;
c = pleaf - > nummarksurfaces ;
if ( c )
{
do
{
( * mark + + ) - > visframe = q1_framecount ;
} while ( - - c ) ;
}
return ;
}
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node - > plane ;
switch ( plane - > type )
{
case PLANE_X :
dot = r_origin [ 0 ] - plane - > dist ;
break ;
case PLANE_Y :
dot = r_origin [ 1 ] - plane - > dist ;
break ;
case PLANE_Z :
dot = r_origin [ 2 ] - plane - > dist ;
break ;
default :
dot = DotProduct ( r_origin , plane - > normal ) - plane - > dist ;
break ;
}
if ( dot > = 0 )
side = 0 ;
else
side = 1 ;
// recurse down the children, front side first
Q1BSP_RecursiveWorldNode ( node - > children [ side ] , clipflags ) ;
// draw stuff
c = node - > numsurfaces ;
if ( c )
{
surf = cl . worldmodel - > surfaces + node - > firstsurface ;
if ( dot < 0 - BACKFACE_EPSILON )
side = SURF_PLANEBACK ;
else if ( dot > BACKFACE_EPSILON )
side = 0 ;
{
for ( ; c ; c - - , surf + + )
{
if ( surf - > visframe ! = q1_framecount )
continue ;
if ( ( ( dot < 0 ) ^ ! ! ( surf - > flags & SURF_PLANEBACK ) ) )
continue ; // wrong side
Surf_RenderDynamicLightmaps ( surf ) ;
surf - > sbatch - > mesh [ surf - > sbatch - > meshes + + ] = surf - > mesh ;
}
}
}
// recurse down the back side
//GLR_RecursiveWorldNode (node->children[!side], clipflags);
node = node - > children [ ! side ] ;
goto start ;
}
static void Q1BSP_OrthoRecursiveWorldNode ( mnode_t * node , unsigned int clipflags )
{
//when rendering as ortho the front and back sides are technically equal. the only culling comes from frustum culling.
int c , clipped ;
mplane_t * clipplane ;
msurface_t * surf , * * mark ;
mleaf_t * pleaf ;
if ( node - > contents = = Q1CONTENTS_SOLID )
return ; // solid
if ( node - > visframe ! = q1_visframecount )
return ;
for ( c = 0 , clipplane = r_refdef . frustum ; c < r_refdef . frustum_numworldplanes ; c + + , clipplane + + )
{
if ( ! ( clipflags & ( 1 < < c ) ) )
continue ; // don't need to clip against it
clipped = BOX_ON_PLANE_SIDE ( node - > minmaxs , node - > minmaxs + 3 , clipplane ) ;
if ( clipped = = 2 )
return ;
else if ( clipped = = 1 )
clipflags - = ( 1 < < c ) ; // node is entirely on screen
}
// if a leaf node, draw stuff
if ( node - > contents < 0 )
{
pleaf = ( mleaf_t * ) node ;
mark = pleaf - > firstmarksurface ;
c = pleaf - > nummarksurfaces ;
if ( c )
{
do
{
( * mark + + ) - > visframe = q1_framecount ;
} while ( - - c ) ;
}
return ;
}
// recurse down the children
Q1BSP_OrthoRecursiveWorldNode ( node - > children [ 0 ] , clipflags ) ;
Q1BSP_OrthoRecursiveWorldNode ( node - > children [ 1 ] , clipflags ) ;
// draw stuff
c = node - > numsurfaces ;
if ( c )
{
surf = cl . worldmodel - > surfaces + node - > firstsurface ;
for ( ; c ; c - - , surf + + )
{
if ( surf - > visframe ! = q1_framecount )
continue ;
Surf_RenderDynamicLightmaps ( surf ) ;
surf - > sbatch - > mesh [ surf - > sbatch - > meshes + + ] = surf - > mesh ;
}
}
return ;
}
static qbyte * Q1BSP_MarkLeaves ( model_t * model , int clusters [ 2 ] )
{
static qbyte * cvis ;
qbyte * vis ;
mnode_t * node ;
int i ;
int portal = r_refdef . recurse ;
static pvsbuffer_t pvsbuf ;
struct q1bspprv_s * prv = model - > meshinfo ;
q1_framecount = + + prv - > framecount ;
//for portals to work, we need two sets of any pvs caches
//this means lights can still check pvs at the end of the frame despite recursing in the mean time
//however, we still need to invalidate the cache because we only have one 'visframe' field in nodes.
if ( r_refdef . forcevis )
{
vis = r_refdef . forcedvis ;
prv - > oldviewclusters [ 0 ] = - 1 ;
prv - > oldviewclusters [ 1 ] = - 2 ;
cvis = NULL ;
}
else
{
if ( ! portal )
{
if ( ( ( prv - > oldviewclusters [ 0 ] = = clusters [ 0 ] & & prv - > oldviewclusters [ 1 ] = = clusters [ 1 ] ) & & ! r_novis . ival ) | | r_novis . ival & 2 )
if ( cvis )
{
q1_visframecount = prv - > visframecount ;
return cvis ;
}
prv - > oldviewclusters [ 0 ] = clusters [ 0 ] ;
prv - > oldviewclusters [ 1 ] = clusters [ 1 ] ;
}
else
{
prv - > oldviewclusters [ 0 ] = - 1 ;
prv - > oldviewclusters [ 1 ] = - 2 ;
cvis = NULL ;
}
if ( r_novis . ival )
{
if ( pvsbuf . buffersize < model - > pvsbytes )
pvsbuf . buffer = BZ_Realloc ( pvsbuf . buffer , pvsbuf . buffersize = model - > pvsbytes ) ;
vis = cvis = pvsbuf . buffer ;
memset ( pvsbuf . buffer , 0xff , pvsbuf . buffersize ) ;
prv - > oldviewclusters [ 0 ] = - 1 ;
prv - > oldviewclusters [ 1 ] = - 2 ;
}
else
{
if ( clusters [ 1 ] > = 0 & & clusters [ 1 ] ! = clusters [ 0 ] )
{
vis = cvis = model - > funcs . ClusterPVS ( model , clusters [ 0 ] , & pvsbuf , PVM_REPLACE ) ;
vis = cvis = model - > funcs . ClusterPVS ( model , clusters [ 1 ] , & pvsbuf , PVM_MERGE ) ;
}
else
vis = cvis = model - > funcs . ClusterPVS ( model , clusters [ 0 ] , & pvsbuf , PVM_FAST ) ;
}
}
prv - > visframecount + + ;
q1_visframecount = prv - > visframecount ;
if ( clusters [ 0 ] < 0 )
{
//to improve spectating, when the camera is in a wall, we ignore any sky leafs.
//this prevents seeing the upwards-facing sky surfaces within the sky volumes.
//this will not affect inwards facing sky, so sky will basically appear as though it is identical to solid brushes.
for ( i = 0 ; i < model - > numclusters ; i + + )
{
if ( vis [ i > > 3 ] & ( 1 < < ( i & 7 ) ) )
{
if ( model - > leafs [ i + 1 ] . contents = = Q1CONTENTS_SKY )
continue ;
node = ( mnode_t * ) & model - > leafs [ i + 1 ] ;
do
{
if ( node - > visframe = = q1_visframecount )
break ;
node - > visframe = q1_visframecount ;
node = node - > parent ;
} while ( node ) ;
}
}
}
else
{
for ( i = 0 ; i < model - > numclusters ; i + + )
{
if ( vis [ i > > 3 ] & ( 1 < < ( i & 7 ) ) )
{
node = ( mnode_t * ) & model - > leafs [ i + 1 ] ;
do
{
if ( node - > visframe = = q1_visframecount )
break ;
node - > visframe = q1_visframecount ;
node = node - > parent ;
} while ( node ) ;
}
}
}
return vis ;
}
static void Q1BSP_PrepareFrame ( model_t * model , refdef_t * refdef , int area , int clusters [ 2 ] , pvsbuffer_t * vis , qbyte * * entvis_out , qbyte * * surfvis_out )
{
* entvis_out = Q1BSP_MarkLeaves ( model , clusters ) ;
if ( vis - > buffersize < model - > pvsbytes )
vis - > buffer = BZ_Realloc ( vis - > buffer , vis - > buffersize = model - > pvsbytes ) ;
q1frustumvis = vis - > buffer ;
memset ( q1frustumvis , 0 , model - > pvsbytes ) ;
if ( model ! = cl . worldmodel )
; //global abuse...
else if ( r_refdef . useperspective )
Q1BSP_RecursiveWorldNode ( model - > nodes , 0x1f ) ;
else
Q1BSP_OrthoRecursiveWorldNode ( model - > nodes , 0x1f ) ;
* surfvis_out = q1frustumvis ;
}
2004-08-21 01:25:48 +00:00
# endif
/*
Rendering functions ( Client only )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Server only functions
*/
2021-12-20 10:06:09 +00:00
# ifdef HAVE_SERVER
2017-07-28 01:49:25 +00:00
static qbyte * Q1BSP_ClusterPVS ( model_t * model , int cluster , pvsbuffer_t * buffer , pvsmerge_t merge ) ;
2004-08-21 01:25:48 +00:00
//does the recursive work of Q1BSP_FatPVS
2019-07-02 04:12:20 +00:00
static void SV_Q1BSP_AddToFatPVS ( model_t * mod , const vec3_t org , mnode_t * node , pvsbuffer_t * pvsbuffer )
2004-08-21 01:25:48 +00:00
{
mplane_t * plane ;
2020-10-26 06:30:35 +00:00
float d ;
2004-08-21 01:25:48 +00:00
while ( 1 )
{
// if this is a leaf, accumulate the pvs bits
if ( node - > contents < 0 )
{
if ( node - > contents ! = Q1CONTENTS_SOLID )
{
2017-07-28 01:49:25 +00:00
Q1BSP_ClusterPVS ( mod , ( ( mleaf_t * ) node - mod - > leafs ) - 1 , pvsbuffer , PVM_MERGE ) ;
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
2017-06-21 01:24:25 +00:00
SV_Q1BSP_AddToFatPVS ( mod , org , node - > children [ 0 ] , pvsbuffer ) ;
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 .
= = = = = = = = = = = = =
*/
2019-07-02 04:12:20 +00:00
static unsigned int Q1BSP_FatPVS ( model_t * mod , const vec3_t org , pvsbuffer_t * pvsbuffer , qboolean add )
2004-08-21 01:25:48 +00:00
{
2017-06-21 01:24:25 +00:00
if ( pvsbuffer - > buffersize < mod - > pvsbytes )
pvsbuffer - > buffer = BZ_Realloc ( pvsbuffer - > buffer , pvsbuffer - > buffersize = mod - > pvsbytes ) ;
2004-08-21 01:25:48 +00:00
if ( ! add )
2017-06-21 01:24:25 +00:00
Q_memset ( pvsbuffer - > buffer , 0 , mod - > pvsbytes ) ;
SV_Q1BSP_AddToFatPVS ( mod , org , mod - > nodes , pvsbuffer ) ;
return mod - > pvsbytes ;
2004-08-21 01:25:48 +00:00
}
2011-01-29 19:53:38 +00:00
# endif
2019-07-02 04:12:20 +00:00
static qboolean Q1BSP_EdictInFatPVS ( model_t * mod , const struct pvscache_s * ent , const qbyte * pvs , const int * areas )
2004-08-21 01:25:48 +00:00
{
int i ;
2005-05-13 10:42:48 +00:00
2019-07-02 04:12:20 +00:00
//if (areas)areas[0] is the area count... but q1bsp has no areas so we ignore it entirely.
2019-04-07 16:41:09 +00:00
if ( ent - > num_leafs < 0 )
2005-05-13 10:42:48 +00:00
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 .
= = = = = = = = = = = = = = =
*/
2019-07-02 04:12:20 +00:00
static void Q1BSP_RFindTouchedLeafs ( model_t * wm , struct pvscache_s * ent , mnode_t * node , const float * mins , const float * maxs )
2004-08-21 01:25:48 +00:00
{
mplane_t * splitplane ;
mleaf_t * leaf ;
int sides ;
int leafnum ;
// add an efrag if the node is a leaf
2016-01-18 05:22:07 +00:00
if ( node - > contents < 0 )
2004-08-21 01:25:48 +00:00
{
2016-01-18 05:22:07 +00:00
//ignore solid leafs. this should include leaf 0 (which has no pvs info)
if ( node - > contents = = Q1CONTENTS_SOLID )
return ;
2019-04-07 16:41:09 +00:00
if ( ( unsigned ) ent - > num_leafs > = MAX_ENT_LEAFS )
2005-05-13 10:42:48 +00:00
{
2019-04-07 16:41:09 +00:00
ent - > num_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
}
2019-07-02 04:12:20 +00:00
static void Q1BSP_FindTouchedLeafs ( model_t * mod , struct pvscache_s * ent , const float * mins , const 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
= = = = = = = = = = = = = = = = = = =
*/
2017-06-21 01:24:25 +00:00
static qbyte * Q1BSP_DecompressVis ( qbyte * in , model_t * model , qbyte * decompressed , unsigned int buffersize , qboolean merge )
2005-08-26 22:56:51 +00:00
{
int c ;
qbyte * out ;
int row ;
2014-05-23 02:02:51 +00:00
row = ( model - > numclusters + 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 ( ! 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
}
2017-06-21 01:24:25 +00:00
if ( merge )
2005-08-26 22:56:51 +00:00
{
2017-06-21 01:24:25 +00:00
do
2005-08-26 22:56:51 +00:00
{
2017-06-21 01:24:25 +00:00
if ( * in )
{
* out + + | = * in + + ;
continue ;
}
out + = in [ 1 ] ;
in + = 2 ;
} while ( out - decompressed < row ) ;
}
else
{
do
2005-08-26 22:56:51 +00:00
{
2017-06-21 01:24:25 +00:00
if ( * in )
{
* out + + = * in + + ;
continue ;
}
c = in [ 1 ] ;
in + = 2 ;
2018-12-11 00:20:59 +00:00
if ( ( out - decompressed ) + c > row )
{
2018-12-06 05:51:24 +00:00
c = row - ( out - decompressed ) ;
Con_DPrintf ( " warning: Vis decompression overrun \n " ) ;
}
2017-06-21 01:24:25 +00:00
while ( c )
{
* out + + = 0 ;
c - - ;
}
} while ( out - decompressed < row ) ;
}
2006-03-04 20:43:48 +00:00
2005-08-26 22:56:51 +00:00
return decompressed ;
}
2017-06-21 01:24:25 +00:00
static pvsbuffer_t mod_novis ;
static pvsbuffer_t mod_tempvis ;
2005-08-26 22:56:51 +00:00
2017-07-28 01:49:25 +00:00
void Q1BSP_Shutdown ( void )
2005-08-26 22:56:51 +00:00
{
2017-07-28 01:49:25 +00:00
Z_Free ( mod_novis . buffer ) ;
memset ( & mod_novis , 0 , sizeof ( mod_novis ) ) ;
Z_Free ( mod_tempvis . buffer ) ;
memset ( & mod_tempvis , 0 , sizeof ( mod_tempvis ) ) ;
2005-08-26 22:56:51 +00:00
}
2014-05-23 02:02:51 +00:00
//pvs is 1-based. clusters are 0-based. otherwise, q1bsp has a 1:1 mapping.
2017-06-21 01:24:25 +00:00
static qbyte * Q1BSP_ClusterPVS ( model_t * model , int cluster , pvsbuffer_t * buffer , pvsmerge_t merge )
2005-08-26 22:56:51 +00:00
{
2014-05-23 02:02:51 +00:00
if ( cluster = = - 1 )
2017-06-21 01:24:25 +00:00
{
if ( merge = = PVM_FAST )
{
if ( mod_novis . buffersize < model - > pvsbytes )
{
mod_novis . buffer = BZ_Realloc ( mod_novis . buffer , mod_novis . buffersize = model - > pvsbytes ) ;
memset ( mod_novis . buffer , 0xff , mod_novis . buffersize ) ;
}
return mod_novis . buffer ;
}
if ( buffer - > buffersize < model - > pvsbytes )
buffer - > buffer = BZ_Realloc ( buffer - > buffer , buffer - > buffersize = model - > pvsbytes ) ;
memset ( buffer - > buffer , 0xff , model - > pvsbytes ) ;
return buffer - > buffer ;
}
2014-05-23 02:02:51 +00:00
2017-06-21 01:24:25 +00:00
if ( merge = = PVM_FAST & & model - > pvs )
return model - > pvs + cluster * model - > pvsbytes ;
2017-07-04 05:07:51 +00:00
cluster + + ;
2014-05-23 02:02:51 +00:00
if ( ! buffer )
2017-06-21 01:24:25 +00:00
buffer = & mod_tempvis ;
2014-05-23 02:02:51 +00:00
2017-06-21 01:24:25 +00:00
if ( buffer - > buffersize < model - > pvsbytes )
buffer - > buffer = BZ_Realloc ( buffer - > buffer , buffer - > buffersize = model - > pvsbytes ) ;
return Q1BSP_DecompressVis ( model - > leafs [ cluster ] . compressed_vis , model , buffer - > buffer , buffer - > buffersize , merge = = PVM_MERGE ) ;
2005-08-26 22:56:51 +00:00
}
2021-11-03 20:30:40 +00:00
static qbyte * Q1BSP_ClusterPHS ( model_t * model , int cluster , pvsbuffer_t * buffer )
2017-06-21 01:24:25 +00:00
{
2021-11-03 20:30:40 +00:00
return model - > phs + cluster * model - > pvsbytes ;
}
2017-06-21 01:24:25 +00:00
2005-08-26 22:56:51 +00:00
//returns the leaf number, which is used as a bit index into the pvs.
2014-05-23 02:02:51 +00:00
static int Q1BSP_LeafnumForPoint ( model_t * model , vec3_t p )
2005-08-26 22:56:51 +00:00
{
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
{
2021-11-03 20:30:40 +00:00
Sys_Error ( " Q1BSP_LeafnumForPoint: bad model " ) ;
2005-08-26 22:56:51 +00:00
}
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 ) ;
}
2019-07-02 04:12:20 +00:00
static void Q1BSP_ClustersInSphere_Union ( mleaf_t * firstleaf , const vec3_t center , float radius , mnode_t * node , qbyte * out , qbyte * unionwith )
2017-10-31 22:52:58 +00:00
{ //this is really for rtlights.
float t1 , t2 ;
mplane_t * plane ;
while ( 1 )
{
if ( node - > contents < 0 )
{ //leaf! mark/merge it.
size_t c = ( mleaf_t * ) node - firstleaf ;
2017-12-14 21:12:11 +00:00
if ( c = = - 1 )
return ;
2017-10-31 22:52:58 +00:00
if ( unionwith )
out [ c > > 3 ] | = ( 1 < < ( c & 7 ) ) & unionwith [ c > > 3 ] ;
else
out [ c > > 3 ] | = ( 1 < < ( c & 7 ) ) ;
return ;
}
plane = node - > plane ;
if ( plane - > type < 3 )
t1 = center [ plane - > type ] - plane - > dist ;
else
t1 = DotProduct ( plane - > normal , center ) - plane - > dist ;
t2 = t1 - radius ;
t1 = t1 + radius ;
//if the sphere is fully to one side, only walk that side.
if ( t1 > 0 & & t2 > 0 )
{
node = node - > children [ 0 ] ;
continue ;
}
if ( t1 < 0 & & t2 < 0 )
{
node = node - > children [ 1 ] ;
continue ;
}
//both sides are within the sphere
Q1BSP_ClustersInSphere_Union ( firstleaf , center , radius , node - > children [ 0 ] , out , unionwith ) ;
node = node - > children [ 1 ] ;
continue ;
}
}
2021-08-04 21:17:31 +00:00
static qbyte * Q1BSP_ClustersInSphere ( model_t * mod , const vec3_t center , float radius , pvsbuffer_t * fte_restrict pvsbuffer , const qbyte * fte_restrict unionwith )
2017-10-31 22:52:58 +00:00
{
if ( ! mod )
2021-11-03 20:30:40 +00:00
Sys_Error ( " Q1BSP_ClustersInSphere: bad model " ) ;
2017-10-31 22:52:58 +00:00
if ( ! mod - > nodes )
return NULL ;
if ( pvsbuffer - > buffersize < mod - > pvsbytes )
pvsbuffer - > buffer = BZ_Realloc ( pvsbuffer - > buffer , pvsbuffer - > buffersize = mod - > pvsbytes ) ;
Q_memset ( pvsbuffer - > buffer , 0 , mod - > pvsbytes ) ;
2017-12-14 21:12:11 +00:00
Q1BSP_ClustersInSphere_Union ( mod - > leafs + 1 , center , radius , mod - > nodes , pvsbuffer - > buffer , NULL ) ; //unionwith);
2017-10-31 22:52:58 +00:00
return pvsbuffer - > buffer ;
}
2014-05-23 02:02:51 +00:00
//returns the leaf number, which is used as a direct bit index into the pvs.
//-1 for invalid
2019-07-02 04:12:20 +00:00
static int Q1BSP_ClusterForPoint ( model_t * model , const vec3_t p , int * area )
2014-05-23 02:02:51 +00:00
{
mnode_t * node ;
float d ;
mplane_t * plane ;
if ( ! model )
{
2021-11-03 20:30:40 +00:00
Sys_Error ( " Q1BSP_ClusterForPoint: bad model " ) ;
2014-05-23 02:02:51 +00:00
}
2019-07-02 04:12:20 +00:00
if ( area )
* area = 0 ; //no areas with q1bsp.
2014-05-23 02:02:51 +00:00
if ( ! model - > nodes )
return - 1 ;
node = model - > nodes ;
while ( 1 )
{
if ( node - > contents < 0 )
return ( ( mleaf_t * ) node - model - > leafs ) - 1 ;
plane = node - > plane ;
d = DotProduct ( p , plane - > normal ) - plane - > dist ;
if ( d > 0 )
node = node - > children [ 0 ] ;
else
node = node - > children [ 1 ] ;
}
return - 1 ; // never reached
}
2005-08-26 22:56:51 +00:00
2021-11-03 20:30:40 +00:00
static void Q1BSP_InfoForPoint ( struct model_s * mod , vec3_t pos , int * area , int * cluster , unsigned int * contentbits )
{
mnode_t * node ;
float d ;
mplane_t * plane ;
* area = 0 ; //no areas with q1bsp.
* cluster = - 1 ;
* contentbits = FTECONTENTS_SOLID ;
if ( ! mod - > nodes )
return ;
node = mod - > nodes ;
while ( 1 )
{
if ( node - > contents < 0 )
{
* cluster = ( ( mleaf_t * ) node - mod - > leafs ) - 1 ;
* contentbits = Q1BSP_TranslateContents ( ( ( mleaf_t * ) node ) - > contents ) ;
return ; //we're done
}
plane = node - > plane ;
d = DotProduct ( pos , plane - > normal ) - plane - > dist ;
if ( d > 0 )
node = node - > children [ 0 ] ;
else
node = node - > children [ 1 ] ;
}
}
2005-08-26 22:56:51 +00:00
/*
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 )
{
}
2017-01-13 00:39:50 +00:00
//sets up the functions a server needs.
//fills in bspfuncs_t
void Q1BSP_SetModelFuncs ( model_t * mod )
{
2021-11-03 20:30:40 +00:00
# ifdef HAVE_SERVER
2017-01-13 00:39:50 +00:00
mod - > funcs . FatPVS = Q1BSP_FatPVS ;
# endif
mod - > funcs . EdictInFatPVS = Q1BSP_EdictInFatPVS ;
mod - > funcs . FindTouchedLeafs = Q1BSP_FindTouchedLeafs ;
2017-10-31 22:52:58 +00:00
mod - > funcs . ClustersInSphere = Q1BSP_ClustersInSphere ;
2017-01-13 00:39:50 +00:00
mod - > funcs . ClusterForPoint = Q1BSP_ClusterForPoint ;
mod - > funcs . ClusterPVS = Q1BSP_ClusterPVS ;
2021-11-03 20:30:40 +00:00
mod - > funcs . ClusterPHS = Q1BSP_ClusterPHS ;
2017-01-13 00:39:50 +00:00
mod - > funcs . NativeTrace = Q1BSP_Trace ;
mod - > funcs . PointContents = Q1BSP_PointContents ;
2021-04-14 05:21:04 +00:00
2021-12-20 10:06:09 +00:00
mod - > funcs . InfoForPoint = Q1BSP_InfoForPoint ;
2021-11-03 20:30:40 +00:00
# ifdef HAVE_CLIENT
2021-04-14 05:21:04 +00:00
mod - > funcs . LightPointValues = GLQ1BSP_LightPointValues ;
mod - > funcs . MarkLights = Q1BSP_MarkLights ;
mod - > funcs . StainNode = Q1BSP_StainNode ;
2021-11-03 20:30:40 +00:00
# ifdef RTLIGHTS
mod - > funcs . GenerateShadowMesh = Q1BSP_GenerateShadowMesh ;
# endif
2021-12-20 10:06:09 +00:00
mod - > funcs . PrepareFrame = Q1BSP_PrepareFrame ;
2021-11-03 20:30:40 +00:00
2021-12-20 10:06:09 +00:00
{
struct q1bspprv_s * prv = mod - > meshinfo = ZG_Malloc ( & mod - > memgroup , sizeof ( struct q1bspprv_s ) ) ;
2021-12-20 10:07:46 +00:00
prv - > oldviewclusters [ 0 ] = - 1 ; //make sure its reset properly.
prv - > oldviewclusters [ 1 ] = - 1 ;
2021-12-20 10:06:09 +00:00
}
# endif
2017-01-13 00:39:50 +00:00
}
# endif
/*
Init stuff
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BSPX Stuff
*/
2021-05-28 07:07:48 +00:00
# include "fs.h"
2017-01-13 00:39:50 +00:00
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 ;
2018-07-24 13:59:42 +00:00
struct bspx_header_s {
2012-02-27 12:23:15 +00:00
char id [ 4 ] ; // 'BSPX'
int numlumps ;
bspx_lump_t lumps [ 1 ] ;
2018-07-24 13:59:42 +00:00
} ;
2012-02-27 12:23:15 +00:00
//supported lumps:
//RGBLIGHTING (.lit)
2018-11-19 06:37:25 +00:00
//LIGHTING_E5BGR9 (hdr lit)
2012-02-27 12:23:15 +00:00
//LIGHTINGDIR (.lux)
2018-11-19 06:37:25 +00:00
//LMSHIFT (lightmap scaling)
//LMOFFSET (lightmap scaling)
//LMSTYLE (lightmap scaling)
//VERTEXNORMALS (smooth specular)
//BRUSHLIST (no hull size issues)
//ENVMAP (cubemaps)
//SURFENVMAP (cubemaps)
2018-07-24 13:59:42 +00:00
void * BSPX_FindLump ( bspx_header_t * bspxheader , void * mod_base , char * lumpname , int * lumpsize )
2012-02-27 12:23:15 +00:00
{
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 ;
2018-07-24 13:59:42 +00:00
return ( char * ) mod_base + bspxheader - > lumps [ i ] . fileofs ;
2012-02-27 12:23:15 +00:00
}
}
return NULL ;
}
2021-05-28 07:07:48 +00:00
bspx_header_t * BSPX_Setup ( model_t * mod , char * filebase , size_t filelen , lump_t * lumps , size_t numlumps )
2012-02-27 12:23:15 +00:00
{
2021-05-28 07:07:48 +00:00
size_t i ;
size_t offs = 0 ;
2012-02-27 12:23:15 +00:00
bspx_header_t * h ;
for ( i = 0 ; i < numlumps ; i + + , lumps + + )
{
if ( offs < lumps - > fileofs + lumps - > filelen )
offs = lumps - > fileofs + lumps - > filelen ;
}
offs = ( offs + 3 ) & ~ 3 ;
2018-07-24 13:59:42 +00:00
if ( offs + sizeof ( * h ) > filelen )
2021-05-28 07:07:48 +00:00
h = NULL ; /*no space for it*/
else
2012-02-27 12:23:15 +00:00
{
2021-05-28 07:07:48 +00:00
h = ( bspx_header_t * ) ( filebase + offs ) ;
i = LittleLong ( h - > numlumps ) ;
/*verify the header*/
if ( * ( int * ) h - > id ! = ( ( ' B ' < < 0 ) | ( ' S ' < < 8 ) | ( ' P ' < < 16 ) | ( ' X ' < < 24 ) ) | |
i < 0 | |
offs + sizeof ( * h ) + sizeof ( h - > lumps [ 0 ] ) * ( i - 1 ) > filelen )
h = NULL ;
else
{
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 NULL ; //some sort of corruption/truncation.
2021-06-22 14:40:53 +00:00
if ( offs < h - > lumps [ i ] . fileofs + h - > lumps [ i ] . filelen )
offs = h - > lumps [ i ] . fileofs + h - > lumps [ i ] . filelen ;
2021-05-28 07:07:48 +00:00
}
}
}
2023-04-11 07:25:15 +00:00
if ( offs < filelen & & mod & & ! mod - > archive & & mod_loadmappackages . ival & & filelen - offs > 22 ) //end-of-central-dir being 22 bytes sets a minimum zip size, which should slightly reduce false-positives.
2021-05-28 07:07:48 +00:00
{ //we have some sort of trailing junk... is it a zip?...
2021-11-03 20:30:40 +00:00
Mod_LoadMapArchive ( mod , filebase + offs , filelen - offs ) ;
2018-07-24 13:59:42 +00:00
}
return h ;
}
2021-12-20 10:06:09 +00:00
# ifndef HAVE_CLIENT
2018-08-04 07:05:20 +00:00
void BSPX_LoadEnvmaps ( model_t * mod , bspx_header_t * bspx , void * mod_base )
{
}
# else
2018-07-24 13:59:42 +00:00
/*
void * SCR_ScreenShot_Capture ( int fbwidth , int fbheight , int * stride , enum uploadfmt * fmt ) ;
void BSPX_RenderEnvmaps ( model_t * mod )
{
int c , i ;
void * buffer ;
int stride , cubesize ;
uploadfmt_t fmt ;
char filename [ MAX_QPATH ] ;
char olddrawviewmodel [ 64 ] ; //hack, so we can set r_drawviewmodel to 0 so that it doesn't appear in screenshots even if the csqc is generating new data.
vec3_t oldangles ;
const struct
{
vec3_t angle ;
const char * postfix ;
qboolean verticalflip ;
qboolean horizontalflip ;
} sides [ ] =
{
{ { 0 , 0 , 90 } , " _px " , true } ,
{ { 0 , 180 , - 90 } , " _nx " , true } ,
{ { 0 , 90 , 0 } , " _py " , true } , //upside down
{ { 0 , 270 , 0 } , " _ny " , false , true } ,
{ { - 90 , 0 , 90 } , " _pz " , true } ,
{ { 90 , 0 , 90 } , " _nz " , true } ,
} ;
char base [ MAX_QPATH ] ;
COM_FileBase ( cl . worldmodel - > name , base , sizeof ( base ) ) ;
r_refdef . stereomethod = STEREO_OFF ;
Q_strncpyz ( olddrawviewmodel , r_drawviewmodel . string , sizeof ( olddrawviewmodel ) ) ;
Cvar_Set ( & r_drawviewmodel , " 0 " ) ;
VectorCopy ( cl . playerview - > viewangles , oldangles ) ;
for ( c = 0 ; c < mod - > numenvmaps ; c + + )
{
cubesize = mod - > envmaps [ c ] . cubesize ;
if ( cubesize < 1 )
cubesize = 32 ;
VectorCopy ( mod - > envmaps [ c ] . origin , r_refdef . vieworg ) ;
for ( i = 0 ; i < 6 ; i + + )
{
Q_snprintfz ( filename , sizeof ( filename ) , " %s/%i_%i_%i%s.tga " , base , ( int ) mod - > envmaps [ c ] . origin [ 0 ] , ( int ) mod - > envmaps [ c ] . origin [ 1 ] , ( int ) mod - > envmaps [ c ] . origin [ 2 ] , sides [ i ] . postfix ) ;
VectorCopy ( sides [ i ] . angle , cl . playerview - > simangles ) ;
VectorCopy ( cl . playerview - > simangles , cl . playerview - > viewangles ) ;
buffer = SCR_ScreenShot_Capture ( cubesize , cubesize , & stride , & fmt ) ;
if ( buffer )
{
char sysname [ 1024 ] ;
if ( sides [ i ] . horizontalflip )
{
int y , x , p ;
int pxsize ;
char * bad = buffer ;
char * in = buffer , * out ;
switch ( fmt )
{
case TF_RGBA32 :
case TF_BGRA32 :
case TF_RGBX32 :
case TF_BGRX32 :
pxsize = 4 ;
break ;
case TF_RGB24 :
case TF_BGR24 :
pxsize = 3 ;
break ;
2019-04-07 16:41:09 +00:00
case PTI_RGBA16F :
2018-07-24 13:59:42 +00:00
pxsize = 8 ;
break ;
2019-04-07 16:41:09 +00:00
case PTI_RGBA32F :
2018-07-24 13:59:42 +00:00
pxsize = 16 ;
break ;
default : //erk!
pxsize = 1 ;
break ;
}
buffer = out = BZ_Malloc ( cubesize * cubesize * pxsize ) ;
for ( y = 0 ; y < cubesize ; y + + , in + = abs ( stride ) , out + = cubesize * pxsize )
{
for ( x = 0 ; x < cubesize * pxsize ; x + = pxsize )
{
for ( p = 0 ; p < pxsize ; p + + )
out [ x + p ] = in [ ( cubesize - 1 ) * pxsize - x + p ] ;
}
}
BZ_Free ( bad ) ;
if ( stride < 0 )
stride = - cubesize * pxsize ;
else
stride = cubesize * pxsize ;
}
if ( sides [ i ] . verticalflip )
stride = - stride ;
if ( SCR_ScreenShot ( filename , FS_GAMEONLY , & buffer , 1 , stride , cubesize , cubesize , fmt ) )
{
FS_NativePath ( filename , FS_GAMEONLY , sysname , sizeof ( sysname ) ) ;
Con_Printf ( " Wrote %s \n " , sysname ) ;
}
else
{
FS_NativePath ( filename , FS_GAMEONLY , sysname , sizeof ( sysname ) ) ;
Con_Printf ( " Failed to write %s \n " , sysname ) ;
}
BZ_Free ( buffer ) ;
}
}
}
Cvar_Set ( & r_drawviewmodel , olddrawviewmodel ) ;
VectorCopy ( oldangles , cl . playerview - > viewangles ) ;
}
*/
void BSPX_LoadEnvmaps ( model_t * mod , bspx_header_t * bspx , void * mod_base )
{
unsigned int * envidx , idx ;
int i ;
char base [ MAX_QPATH ] ;
char imagename [ MAX_QPATH ] ;
menvmap_t * out ;
int count ;
denvmap_t * in = BSPX_FindLump ( bspx , mod_base , " ENVMAP " , & count ) ;
2019-10-07 04:51:17 +00:00
mod - > envmaps = NULL ;
mod - > numenvmaps = 0 ;
if ( ! mod_loadsurfenvmaps . ival )
return ;
2018-07-24 13:59:42 +00:00
if ( count % sizeof ( * in ) )
return ; //erk
count / = sizeof ( * in ) ;
if ( ! count )
return ;
out = ZG_Malloc ( & mod - > memgroup , sizeof ( * out ) * count ) ;
mod - > envmaps = out ;
mod - > numenvmaps = count ;
COM_FileBase ( mod - > name , base , sizeof ( base ) ) ;
for ( i = 0 ; i < count ; i + + )
{
out [ i ] . origin [ 0 ] = LittleFloat ( in [ i ] . origin [ 0 ] ) ;
out [ i ] . origin [ 1 ] = LittleFloat ( in [ i ] . origin [ 1 ] ) ;
out [ i ] . origin [ 2 ] = LittleFloat ( in [ i ] . origin [ 2 ] ) ;
out [ i ] . cubesize = LittleLong ( in [ i ] . cubesize ) ;
2018-08-02 20:10:43 +00:00
Q_snprintfz ( imagename , sizeof ( imagename ) , " textures/env/%s_%i_%i_%i " , base , ( int ) mod - > envmaps [ i ] . origin [ 0 ] , ( int ) mod - > envmaps [ i ] . origin [ 1 ] , ( int ) mod - > envmaps [ i ] . origin [ 2 ] ) ;
2019-10-18 08:37:38 +00:00
out [ i ] . image = Image_GetTexture ( imagename , NULL , IF_TEXTYPE_CUBE | IF_NOREPLACE , NULL , NULL , out [ i ] . cubesize , out [ i ] . cubesize , PTI_INVALID ) ;
2018-07-24 13:59:42 +00:00
}
//now update surface lists.
envidx = BSPX_FindLump ( bspx , mod_base , " SURFENVMAP " , & i ) ;
if ( i / sizeof ( * envidx ) = = mod - > numsurfaces )
{
for ( i = 0 ; i < mod - > numsurfaces ; i + + )
{
idx = LittleLong ( envidx [ i ] ) ;
if ( idx < ( unsigned int ) count )
mod - > surfaces [ i ] . envmap = out [ idx ] . image ;
}
}
}
struct bspxrw
{
const char * fname ;
char * origfile ;
qofs_t origsize ;
int lumpofs ;
2018-11-19 06:37:25 +00:00
fromgame_t fg ;
2018-07-24 13:59:42 +00:00
size_t corelumps ;
size_t totallumps ;
struct
{
char lumpname [ 24 ] ; // up to 23 chars, zero-padded
void * data ; // from file start
qofs_t filelen ;
} * lumps ;
} ;
void Mod_BSPXRW_Free ( struct bspxrw * ctx )
{
FS_FreeFile ( ctx - > origfile ) ;
Z_Free ( ctx - > lumps ) ;
ctx - > corelumps = ctx - > totallumps = 0 ;
ctx - > origfile = NULL ;
}
void Mod_BSPXRW_Write ( struct bspxrw * ctx )
{
# if 1
vfsfile_t * f = FS_OpenVFS ( ctx - > fname , " wb " , FS_GAMEONLY ) ;
if ( f )
{
qofs_t bspxofs ;
size_t i , j ;
int pad , paddata = 0 ;
int nxlumps = ctx - > totallumps - ctx - > corelumps ;
lump_t * lumps = alloca ( sizeof ( * lumps ) * ctx - > corelumps ) ;
bspx_lump_t * xlumps = alloca ( sizeof ( * xlumps ) * ( ctx - > totallumps - ctx - > corelumps ) ) ;
//bsp header info
VFS_WRITE ( f , ctx - > origfile , ctx - > lumpofs ) ;
VFS_WRITE ( f , lumps , sizeof ( lumps [ 0 ] ) * ctx - > corelumps ) ; //placeholder
//orig lumps
for ( i = 0 ; i < ctx - > corelumps ; i + + )
{
lumps [ i ] . fileofs = VFS_TELL ( f ) ;
lumps [ i ] . filelen = ctx - > lumps [ i ] . filelen ;
VFS_WRITE ( f , ctx - > lumps [ i ] . data , ctx - > lumps [ i ] . filelen ) ;
//ALL lumps must be 4-aligned, so pad if needed.
pad = ( ( ctx - > lumps [ i ] . filelen + 3 ) & ~ 3 ) - ctx - > lumps [ i ] . filelen ;
VFS_WRITE ( f , & paddata , pad ) ;
}
//bspx header
VFS_WRITE ( f , " BSPX " , 4 ) ;
VFS_WRITE ( f , & nxlumps , sizeof ( nxlumps ) ) ;
bspxofs = VFS_TELL ( f ) ;
VFS_WRITE ( f , xlumps , sizeof ( xlumps [ 0 ] ) * ( ctx - > totallumps - ctx - > corelumps ) ) ; //placeholder
//bspx data
for ( i = 0 ; i < nxlumps ; i + + )
{
j = ctx - > corelumps + i ;
xlumps [ i ] . fileofs = VFS_TELL ( f ) ;
xlumps [ i ] . filelen = ctx - > lumps [ j ] . filelen ;
memcpy ( xlumps [ i ] . lumpname , ctx - > lumps [ j ] . lumpname , sizeof ( xlumps [ i ] . lumpname ) ) ;
VFS_WRITE ( f , ctx - > lumps [ j ] . data , ctx - > lumps [ j ] . filelen ) ;
//ALL lumps must be 4-aligned, so pad if needed.
pad = ( ( ctx - > lumps [ j ] . filelen + 3 ) & ~ 3 ) - ctx - > lumps [ j ] . filelen ;
VFS_WRITE ( f , & paddata , pad ) ;
}
//now rewrite both sets of offsets.
VFS_SEEK ( f , ctx - > lumpofs ) ;
VFS_WRITE ( f , lumps , sizeof ( lumps [ 0 ] ) * ctx - > corelumps ) ;
VFS_SEEK ( f , bspxofs ) ;
VFS_WRITE ( f , xlumps , sizeof ( xlumps [ 0 ] ) * ( ctx - > totallumps - ctx - > corelumps ) ) ;
VFS_CLOSE ( f ) ;
}
# endif
Mod_BSPXRW_Free ( ctx ) ;
}
void Mod_BSPXRW_SetLump ( struct bspxrw * ctx , const char * lumpname , void * data , size_t datasize )
{
int i ;
for ( i = 0 ; i < ctx - > totallumps ; i + + )
{
if ( ! strcmp ( ctx - > lumps [ i ] . lumpname , lumpname ) )
{ //replace the existing lump
ctx - > lumps [ i ] . data = data ;
ctx - > lumps [ i ] . filelen = datasize ;
2012-02-27 12:23:15 +00:00
return ;
2018-07-24 13:59:42 +00:00
}
}
2018-08-04 19:00:19 +00:00
Z_ReallocElements ( ( void * * ) & ctx - > lumps , & ctx - > totallumps , ctx - > totallumps + 1 , sizeof ( * ctx - > lumps ) ) ;
2018-07-24 13:59:42 +00:00
Q_strncpyz ( ctx - > lumps [ i ] . lumpname , lumpname , sizeof ( ctx - > lumps [ i ] . lumpname ) ) ;
ctx - > lumps [ i ] . data = data ;
ctx - > lumps [ i ] . filelen = datasize ;
}
qboolean Mod_BSPXRW_Read ( struct bspxrw * ctx , const char * fname )
{
int i ;
lump_t * l ;
const char * * corelumpnames = NULL ;
bspx_header_t * bspxheader ;
# ifdef Q3BSPS
static const char * q3corelumpnames [ Q3LUMPS_TOTAL ] = { " entities " , " shaders " , " planes " , " nodes " , " leafs " , " leafsurfs " , " leafbrushes " , " submodels " , " brushes " , " brushsides " , " verts " , " indexes " , " fogs " , " surfaces " , " lightmaps " , " lightgrid " , " visibility "
# ifdef RFBSPS
, " lightgrididx "
# endif
} ;
2023-08-11 04:00:01 +00:00
# endif
# ifdef Q2BSPS
static const char * q2corelumpnames [ Q2HEADER_LUMPS ] = { " entities " , " planes " , " vertexes " , " visibility " , " nodes " , " texinfo " , " faces " , " lighting " , " leafs " , " leaffaces " , " leafbrushes " , " edges " , " surfedges " , " models " , " brushes " , " brushsides " , " pop " , " areas " , " areaportals " } ;
2018-07-24 13:59:42 +00:00
# endif
2023-07-12 17:05:21 +00:00
static const char * q1corelumpnames [ HEADER_LUMPS ] = { " entities " , " planes " , " textures " , " vertexes " , " visibility " , " nodes " , " texinfo " , " faces " , " lighting " , " clipnodes " , " leafs " , " marksurfaces " , " edges " , " surfedges " , " models " } ;
2018-07-24 13:59:42 +00:00
ctx - > fname = fname ;
ctx - > origfile = FS_MallocFile ( ctx - > fname , FS_GAME , & ctx - > origsize ) ;
if ( ! ctx - > origfile )
return false ;
ctx - > lumps = 0 ;
ctx - > totallumps = 0 ;
i = LittleLong ( * ( int * ) ctx - > origfile ) ;
switch ( i )
{
case 29 :
case 30 :
ctx - > fg = ( ( i = = 30 ) ? fg_halflife : fg_quake ) ;
ctx - > lumpofs = 4 ;
2023-07-12 17:05:21 +00:00
ctx - > corelumps = HEADER_LUMPS ;
corelumpnames = q1corelumpnames ;
2018-07-24 13:59:42 +00:00
break ;
2023-07-12 17:05:21 +00:00
case ( ' I ' < < 0 ) + ( ' B ' < < 8 ) + ( ' S ' < < 16 ) + ( ' P ' < < 24 ) : //starting with q2.
2018-07-24 13:59:42 +00:00
i = LittleLong ( * ( int * ) ( ctx - > origfile + 4 ) ) ;
ctx - > lumpofs = 8 ;
switch ( i )
{
# ifdef Q2BSPS
case BSPVERSION_Q2 :
// case BSPVERSION_Q2W:
ctx - > fg = fg_quake2 ;
ctx - > corelumps = Q2HEADER_LUMPS ;
2023-08-11 04:00:01 +00:00
corelumpnames = q2corelumpnames ;
2018-07-24 13:59:42 +00:00
break ;
# endif
# ifdef Q3BSPS
case BSPVERSION_Q3 :
case BSPVERSION_RTCW :
ctx - > fg = fg_quake3 ;
ctx - > corelumps = 17 ;
corelumpnames = q3corelumpnames ;
break ;
# endif
default :
Mod_BSPXRW_Free ( ctx ) ;
return false ;
}
break ;
# ifdef RFBSPS
case ( ' R ' < < 0 ) + ( ' B ' < < 8 ) + ( ' S ' < < 16 ) + ( ' P ' < < 24 ) :
case ( ' F ' < < 0 ) + ( ' B ' < < 8 ) + ( ' S ' < < 16 ) + ( ' P ' < < 24 ) :
i = LittleLong ( * ( int * ) ( ctx - > origfile + 4 ) ) ;
ctx - > lumpofs = 8 ;
switch ( i )
{
case BSPVERSION_RBSP :
ctx - > fg = fg_quake3 ;
ctx - > corelumps = 18 ;
corelumpnames = q3corelumpnames ;
break ;
default :
Mod_BSPXRW_Free ( ctx ) ;
return false ;
}
break ;
# endif
default :
Mod_BSPXRW_Free ( ctx ) ;
return false ;
}
l = ( lump_t * ) ( ctx - > origfile + ctx - > lumpofs ) ;
for ( i = 0 ; i < ctx - > corelumps ; i + + )
{
2018-08-04 19:00:19 +00:00
Z_ReallocElements ( ( void * * ) & ctx - > lumps , & ctx - > totallumps , ctx - > totallumps + 1 , sizeof ( * ctx - > lumps ) ) ;
2018-07-24 13:59:42 +00:00
ctx - > lumps [ ctx - > totallumps - 1 ] . data = ctx - > origfile + l [ i ] . fileofs ;
ctx - > lumps [ ctx - > totallumps - 1 ] . filelen = l [ i ] . filelen ;
if ( corelumpnames )
Q_snprintfz ( ctx - > lumps [ ctx - > totallumps - 1 ] . lumpname , sizeof ( ctx - > lumps [ 0 ] . lumpname ) , " %s " , corelumpnames [ i ] ) ;
else
Q_snprintfz ( ctx - > lumps [ ctx - > totallumps - 1 ] . lumpname , sizeof ( ctx - > lumps [ 0 ] . lumpname ) , " lump%u " , i ) ;
}
bspxheader = BSPX_Setup ( NULL , ctx - > origfile , ctx - > origsize , l , ctx - > corelumps ) ;
if ( bspxheader )
{
for ( i = 0 ; i < bspxheader - > numlumps ; i + + )
{
2018-08-04 19:00:19 +00:00
Z_ReallocElements ( ( void * * ) & ctx - > lumps , & ctx - > totallumps , ctx - > totallumps + 1 , sizeof ( * ctx - > lumps ) ) ;
2018-07-24 13:59:42 +00:00
ctx - > lumps [ ctx - > totallumps - 1 ] . data = ctx - > origfile + bspxheader - > lumps [ i ] . fileofs ;
ctx - > lumps [ ctx - > totallumps - 1 ] . filelen = bspxheader - > lumps [ i ] . filelen ;
memcpy ( ctx - > lumps [ ctx - > totallumps - 1 ] . lumpname , bspxheader - > lumps [ i ] . lumpname , sizeof ( ctx - > lumps [ 0 ] . lumpname ) ) ;
}
}
return true ;
}
unsigned int Mod_NearestCubeForSurf ( msurface_t * surf , denvmap_t * envmap , size_t nenvmap )
{ //this is slow, yes.
size_t n , v ;
unsigned int best = ~ 0 ;
float bestdist = FLT_MAX , dist ;
2018-10-14 16:16:34 +00:00
vec3_t diff , mins , maxs , mid ;
2018-07-24 13:59:42 +00:00
2018-10-14 16:16:34 +00:00
if ( surf - > mesh & & surf - > mesh - > numvertexes )
2018-07-24 13:59:42 +00:00
{
2018-10-14 16:16:34 +00:00
VectorCopy ( surf - > mesh - > xyz_array [ 0 ] , mins ) ;
VectorCopy ( surf - > mesh - > xyz_array [ 0 ] , maxs ) ;
for ( v = 1 ; v < surf - > mesh - > numvertexes ; v + + )
2018-11-04 22:22:18 +00:00
AddPointToBounds ( surf - > mesh - > xyz_array [ v ] , mins , maxs ) ;
2018-10-14 16:16:34 +00:00
VectorAvg ( mins , maxs , mid ) ;
2018-07-24 13:59:42 +00:00
for ( n = 0 ; n < nenvmap ; n + + )
{
2018-10-14 16:16:34 +00:00
VectorSubtract ( envmap [ n ] . origin , mid , diff ) ;
2018-11-04 22:22:18 +00:00
#if 0
2018-08-04 07:05:20 +00:00
//axial distance
2018-11-04 22:22:18 +00:00
dist = fabs ( diff [ 0 ] ) + fabs ( diff [ 1 ] ) + fabs ( diff [ 2 ] ) ;
2018-08-04 07:05:20 +00:00
# else
//radial distance (squared)
2018-07-24 13:59:42 +00:00
dist = DotProduct ( diff , diff ) ;
2018-08-04 07:05:20 +00:00
# endif
2018-07-24 13:59:42 +00:00
if ( bestdist > dist )
{
best = n ;
bestdist = dist ;
}
}
2012-02-27 12:23:15 +00:00
}
2018-07-24 13:59:42 +00:00
return best ;
}
int QDECL envmapsort ( const void * av , const void * bv )
{ //sorts cubemaps in order of size, to make texturearrays easier, if ever. The loader can then just make runs.
const denvmap_t * a = av , * b = bv ;
if ( a - > cubesize = = b - > cubesize )
return 0 ;
if ( a - > cubesize > b - > cubesize )
return 1 ;
return - 1 ;
}
void Mod_FindCubemaps_f ( void )
{
struct bspxrw bspctx ;
if ( Mod_BSPXRW_Read ( & bspctx , cl . worldmodel - > name ) )
{
const char * entlump = Mod_GetEntitiesString ( cl . worldmodel ) , * lmp ;
int nest ;
char key [ 1024 ] ;
char value [ 1024 ] ;
qboolean isenvmap ;
float size ;
vec3_t origin ;
denvmap_t * envmap = NULL ; //*nenvmap
size_t nenvmap = 0 ;
unsigned int * envmapidx = NULL ; //*numsurfaces
size_t nenvmapidx = 0 , i ;
2020-10-26 06:30:35 +00:00
2018-07-24 13:59:42 +00:00
//find targetnames, and store their origins so that we can deal with spotlights.
for ( lmp = entlump ; ; )
{
lmp = COM_Parse ( lmp ) ;
if ( com_token [ 0 ] ! = ' { ' )
break ;
isenvmap = false ;
size = 128 ;
VectorClear ( origin ) ;
2012-02-27 12:23:15 +00:00
2018-07-24 13:59:42 +00:00
nest = 1 ;
while ( 1 )
{
lmp = COM_ParseOut ( lmp , key , sizeof ( key ) ) ;
if ( ! lmp )
break ; // error
if ( key [ 0 ] = = ' { ' )
{
nest + + ;
continue ;
}
if ( key [ 0 ] = = ' } ' )
{
nest - - ;
if ( ! nest )
break ; // end of entity
continue ;
}
if ( nest ! = 1 )
continue ;
if ( key [ 0 ] = = ' _ ' )
memmove ( key , key + 1 , strlen ( key ) ) ;
while ( key [ strlen ( key ) - 1 ] = = ' ' ) // remove trailing spaces
key [ strlen ( key ) - 1 ] = 0 ;
lmp = COM_ParseOut ( lmp , value , sizeof ( value ) ) ;
if ( ! lmp )
break ; // error
// now that we have the key pair worked out...
if ( ! strcmp ( " classname " , key ) & & ! strcmp ( value , " env_cubemap " ) )
isenvmap = true ;
else if ( ! strcmp ( " origin " , key ) )
sscanf ( value , " %f %f %f " , & origin [ 0 ] , & origin [ 1 ] , & origin [ 2 ] ) ;
else if ( ! strcmp ( " size " , key ) )
sscanf ( value , " %f " , & size ) ;
}
2020-10-26 06:30:35 +00:00
2018-07-24 13:59:42 +00:00
if ( isenvmap )
{
int e = nenvmap ;
2018-08-04 19:00:19 +00:00
if ( ZF_ReallocElements ( ( void * * ) & envmap , & nenvmap , nenvmap + 1 , sizeof ( * envmap ) ) )
2018-07-24 13:59:42 +00:00
{
VectorCopy ( origin , envmap [ e ] . origin ) ;
envmap [ e ] . cubesize = size ;
}
}
}
if ( nenvmap )
{
2018-10-14 16:16:34 +00:00
qsort ( envmap , nenvmap , sizeof ( * envmap ) , envmapsort ) ; //sort them by size
2018-08-04 19:00:19 +00:00
if ( ZF_ReallocElements ( ( void * * ) & envmapidx , & nenvmapidx , cl . worldmodel - > numsurfaces , sizeof ( * envmapidx ) ) )
2018-07-24 13:59:42 +00:00
{
for ( i = 0 ; i < cl . worldmodel - > numsurfaces ; i + + )
envmapidx [ i ] = Mod_NearestCubeForSurf ( cl . worldmodel - > surfaces + i , envmap , nenvmap ) ;
}
Mod_BSPXRW_SetLump ( & bspctx , " ENVMAP " , envmap , nenvmap * sizeof ( * envmap ) ) ;
Mod_BSPXRW_SetLump ( & bspctx , " SURFENVMAP " , envmapidx , cl . worldmodel - > numsurfaces * sizeof ( * envmapidx ) ) ;
Mod_BSPXRW_Write ( & bspctx ) ;
}
else
{
Con_Printf ( " No cubemaps found on map \n " ) ;
Mod_BSPXRW_Free ( & bspctx ) ;
}
Z_Free ( envmapidx ) ;
Z_Free ( envmap ) ;
}
}
void Mod_Realign_f ( void )
{
struct bspxrw bspctx ;
if ( Mod_BSPXRW_Read ( & bspctx , cl . worldmodel - > name ) )
Mod_BSPXRW_Write ( & bspctx ) ;
}
void Mod_BSPX_List_f ( void )
{
int i ;
struct bspxrw ctx ;
char * fname = Cmd_Argv ( 1 ) ;
if ( ! * fname & & cl . worldmodel )
fname = cl . worldmodel - > name ;
if ( Mod_BSPXRW_Read ( & ctx , fname ) )
{
2023-07-12 17:05:21 +00:00
Con_Printf ( " %s: \n " , fname ) ;
2018-07-24 13:59:42 +00:00
for ( i = 0 ; i < ctx . corelumps ; i + + )
2023-07-12 17:05:21 +00:00
Con_Printf ( " \t %s: %u \n " , ctx . lumps [ i ] . lumpname , ( unsigned int ) ctx . lumps [ i ] . filelen ) ;
2018-07-24 13:59:42 +00:00
for ( ; i < ctx . totallumps ; i + + )
2023-07-12 17:05:21 +00:00
Con_Printf ( " \t %s: %u \n " , ctx . lumps [ i ] . lumpname , ( unsigned int ) ctx . lumps [ i ] . filelen ) ;
2018-07-24 13:59:42 +00:00
Mod_BSPXRW_Free ( & ctx ) ;
}
}
void Mod_BSPX_Strip_f ( void )
{
int i ;
struct bspxrw ctx ;
qboolean found = false ;
if ( Cmd_Argc ( ) ! = 3 )
Con_Printf ( " %s FILENAME NAME: removes an extended lump from the named bsp file \n " , Cmd_Argv ( 0 ) ) ;
else if ( Mod_BSPXRW_Read ( & ctx , Cmd_Argv ( 1 ) ) )
{
for ( i = ctx . corelumps ; i < ctx . totallumps ; )
{
if ( ! Q_strcasecmp ( ctx . lumps [ i ] . lumpname , Cmd_Argv ( 2 ) ) )
{
found = true ;
memmove ( & ctx . lumps [ i ] , & ctx . lumps [ i + 1 ] , sizeof ( ctx . lumps [ 0 ] ) * ( ctx . totallumps - ( i + 1 ) ) ) ;
ctx . totallumps - - ;
}
else
i + + ;
}
if ( found )
Mod_BSPXRW_Write ( & ctx ) ;
else
Mod_BSPXRW_Free ( & ctx ) ;
}
2012-02-27 12:23:15 +00:00
}
2018-08-23 07:04:55 +00:00
image_t * Mod_CubemapForOrigin ( model_t * wmodel , vec3_t org )
{
int i ;
menvmap_t * e ;
float bestdist = FLT_MAX , dist ;
image_t * ret = NULL ;
vec3_t move ;
if ( ! wmodel | | wmodel - > loadstate ! = MLS_LOADED )
return NULL ;
for ( i = 0 , e = wmodel - > envmaps ; i < wmodel - > numenvmaps ; i + + , e + + )
{
VectorSubtract ( org , e - > origin , move ) ;
dist = DotProduct ( move , move ) ;
if ( bestdist > dist )
{
bestdist = dist ;
ret = e - > image ;
}
}
return ret ;
}
2018-08-02 20:10:43 +00:00
# endif