14 Mar 2017

This commit is contained in:
g-cont 2017-03-14 00:00:00 +03:00 committed by Alibek Omarov
parent 410d714276
commit fdc53c3cc1
28 changed files with 774 additions and 384 deletions

View File

@ -78,8 +78,8 @@ typedef struct ref_overview_s
float xLeft;
float xRight;
float xTop;
float xBottom;
float yTop;
float yBottom;
float zFar;
float zNear;
float flZoom;

View File

@ -215,7 +215,7 @@ typedef struct render_api_s
void (*GL_Reserved2)( void );
// Misc renderer functions
void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags );
void (*GL_DrawParticles)( const struct ref_viewpass_s *rvp, qboolean solid_pass );
void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder
int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare );
void (*Host_Error)( const char *error, ... ); // cause Host Error

View File

@ -570,7 +570,10 @@ Set new weapon animation
void CL_WeaponAnim( int iAnim, int body )
{
cl_entity_t *view = &clgame.viewent;
#if 0
if( CL_LocalWeapons() && cl.local.repredicting )
return;
#endif
cl.local.weaponstarttime = 0.0f;
cl.local.weaponsequence = iAnim;
view->curstate.framerate = 1.0f;
@ -940,10 +943,6 @@ void CL_ParseClientData( sizebuf_t *msg )
MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
}
// keep predicted viewmodel index until server receive actual data
if( CL_LocalWeapons() && from_cd->viewmodel == to_cd->viewmodel )
frame->clientdata.viewmodel = cl.local.viewmodel;
// make a local copy of physinfo
Q_strncpy( cls.physinfo, frame->clientdata.physinfo, sizeof( cls.physinfo ));

View File

@ -1281,6 +1281,7 @@ void CL_PredictMovement( qboolean repredicting )
time = frame->time;
stoppoint = ( repredicting ) ? 0 : 1;
cl.local.repredicting = repredicting;
cl.local.onground = -1;
// predict forward until cl.time <= to->senttime
@ -1309,7 +1310,10 @@ void CL_PredictMovement( qboolean repredicting )
CL_PopPMStates();
if(( i == CL_UPDATE_MASK ) || ( !to && !repredicting ))
{
cl.local.repredicting = false;
return; // net hasn't deliver packets in a long time...
}
if( !to )
{
@ -1320,6 +1324,7 @@ void CL_PredictMovement( qboolean repredicting )
if( !CL_IsPredicted( ))
{
cl.local.viewmodel = to->client.viewmodel;
cl.local.repredicting = false;
return;
}
@ -1356,7 +1361,7 @@ void CL_PredictMovement( qboolean repredicting )
cl.local.waterlevel = to->client.waterlevel;
cl.local.usehull = to->playerstate.usehull;
cl.local.viewmodel = to->client.viewmodel;
if( !repredicting ) cl.local.viewmodel = to->client.viewmodel;
if( FBitSet( to->client.flags, FL_ONGROUND ))
{
@ -1417,4 +1422,5 @@ void CL_PredictMovement( qboolean repredicting )
}
VectorCopy( cl.simorg, cl.local.lastorigin );
cl.local.repredicting = false;
}

View File

@ -81,35 +81,19 @@ void V_SetupViewModel( void )
{
cl_entity_t *view = &clgame.viewent;
player_info_t *info = &cl.players[cl.playernum];
static qboolean model_changing = false;
static int skipframe = 0;
if( CL_LocalWeapons() && view->curstate.modelindex != cl.local.viewmodel && !model_changing )
{
model_changing = true;
skipframe = 2; // server ack & server responce
}
if( !cl.local.weaponstarttime )
cl.local.weaponstarttime = cl.time;
// setup the viewent variables
view->curstate.colormap = (info->topcolor & 0xFFFF)|((info->bottomcolor << 8) & 0xFFFF);
view->curstate.number = cl.playernum + 1;
view->index = cl.playernum + 1;
view->curstate.frame = 0.0f;
if( skipframe <= 0 )
{
if( !cl.local.weaponstarttime )
cl.local.weaponstarttime = cl.time;
view->model = Mod_Handle( cl.local.viewmodel );
view->curstate.modelindex = cl.local.viewmodel;
view->curstate.animtime = cl.local.weaponstarttime;
view->curstate.sequence = cl.local.weaponsequence;
model_changing = false;
}
else
{
skipframe--;
}
view->model = Mod_Handle( cl.local.viewmodel );
view->curstate.modelindex = cl.local.viewmodel;
view->curstate.animtime = cl.local.weaponstarttime;
view->curstate.sequence = cl.local.weaponsequence;
}
/*
@ -196,8 +180,8 @@ void V_RefApplyOverview( ref_viewpass_t *rvp )
// compute rectangle
ov->xLeft = -(size_x / 2);
ov->xRight = (size_x / 2);
ov->xTop = -(size_y / 2);
ov->xBottom = (size_y / 2);
ov->yTop = -(size_y / 2);
ov->yBottom = (size_y / 2);
if( CL_IsDevOverviewMode() == 1 )
{
@ -212,8 +196,8 @@ void V_RefApplyOverview( ref_viewpass_t *rvp )
mins[!ov->rotated] += ov->xLeft;
maxs[!ov->rotated] += ov->xRight;
mins[ov->rotated] += ov->xTop;
maxs[ov->rotated] += ov->xBottom;
mins[ov->rotated] += ov->yTop;
maxs[ov->rotated] += ov->yBottom;
rvp->viewangles[0] = 90.0f;
rvp->viewangles[1] = 90.0f;

View File

@ -129,6 +129,7 @@ typedef struct
float interp_amount;
// misc local info
qboolean repredicting; // repredicting in progress
qboolean thirdperson;
float idealpitch;
int viewmodel;
@ -852,7 +853,7 @@ void CL_WeaponAnim( int iAnim, int body );
void CL_ClearEffects( void );
void CL_ClearEfrags( void );
void CL_TestLights( void );
void CL_DrawParticlesExternal( const float *vieworg, const float *fwd, const float *rt, const float *up, uint clipFlags );
void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean solid_pass );
void CL_FireCustomDecal( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags, float scale );
void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags );
void CL_PlayerDecal( int textureIndex, int entityIndex, float *pos );

View File

@ -381,7 +381,7 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
// check bbox
if( Mod_BoxVisible( mins, maxs, Mod_GetCurrentVis( )))
{
if( pvsOnly || !R_CullBox( mins, maxs, RI.clipFlags ))
if( pvsOnly || !R_CullBox( mins, maxs ))
{
// beam is visible
return false;
@ -1010,7 +1010,7 @@ void R_DrawRing(vec3_t source, vec3_t delta, float width, float amplitude, float
return;
// is that box in PVS && frustum?
if( !Mod_BoxVisible( screen, tmp, Mod_GetCurrentVis( )) || R_CullBox( screen, tmp, RI.clipFlags ))
if( !Mod_BoxVisible( screen, tmp, Mod_GetCurrentVis( )) || R_CullBox( screen, tmp ))
{
return;
}

View File

@ -32,59 +32,9 @@ R_CullBox
Returns true if the box is completely outside the frustum
=================
*/
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs, uint clipflags )
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs )
{
uint i, bit;
const mplane_t *p;
// client.dll may use additional passes for render custom mirrors etc
if( r_nocull->value )
return false;
for( i = sizeof( RI.frustum ) / sizeof( RI.frustum[0] ), bit = 1, p = RI.frustum; i > 0; i--, bit++, p++ )
{
if( !FBitSet( clipflags, BIT( bit )))
continue;
switch( p->signbits )
{
case 0:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 1:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 2:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 3:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 4:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 5:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 6:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 7:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
default:
return false;
}
}
return false;
return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 );
}
/*
@ -94,25 +44,9 @@ R_CullSphere
Returns true if the sphere is completely outside the frustum
=================
*/
qboolean R_CullSphere( const vec3_t centre, const float radius, const uint clipflags )
qboolean R_CullSphere( const vec3_t centre, const float radius )
{
uint i, bit;
const mplane_t *p;
// client.dll may use additional passes for render custom mirrors etc
if( r_nocull->value )
return false;
for( i = sizeof( RI.frustum ) / sizeof( RI.frustum[0] ), bit = 1, p = RI.frustum; i > 0; i--, bit++, p++ )
{
if( !FBitSet( clipflags, BIT( bit )))
continue;
if( DotProduct( centre, p->normal ) - p->dist <= -radius )
return true;
}
return false;
return GL_FrustumCullSphere( &RI.frustum, centre, radius, 0 );
}
/*
@ -148,7 +82,7 @@ int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax )
return 1;
}
if( R_CullBox( absmin, absmax, RI.clipFlags ))
if( R_CullBox( absmin, absmax ))
return 1;
return 0;
@ -161,9 +95,8 @@ R_CullSurface
cull invisible surfaces
=================
*/
qboolean R_CullSurface( msurface_t *surf, uint clipflags )
qboolean R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags )
{
mextrasurf_t *info;
cl_entity_t *e = RI.currententity;
if( !surf || !surf->texinfo || !surf->texinfo->texture )
@ -188,46 +121,57 @@ qboolean R_CullSurface( msurface_t *surf, uint clipflags )
if( r_faceplanecull->value && glState.faceCull != 0 )
{
if( e->curstate.scale == 0.0f )
if( e->curstate.scale == 0.0f && !VectorIsNull( surf->plane->normal ))
{
if( !VectorIsNull( surf->plane->normal ))
float dist;
// can use normal.z for world (optimisation)
if( RI.drawOrtho )
{
float dist;
vec3_t orthonormal;
if( RI.drawOrtho ) dist = surf->plane->normal[2];
else dist = PlaneDiff( tr.modelorg, surf->plane );
if( e == clgame.entities || R_StaticEntity( e ))
orthonormal[2] = surf->plane->normal[2];
else Matrix4x4_VectorRotate( RI.objectMatrix, surf->plane->normal, orthonormal );
if( glState.faceCull == GL_FRONT || ( RI.params & RP_MIRRORVIEW ))
dist = orthonormal[2];
}
else dist = PlaneDiff( tr.modelorg, surf->plane );
if( glState.faceCull == GL_FRONT || ( RI.params & RP_MIRRORVIEW ))
{
if( surf->flags & SURF_PLANEBACK )
{
if( surf->flags & SURF_PLANEBACK )
{
if( dist >= -BACKFACE_EPSILON )
return true; // wrong side
}
else
{
if( dist <= BACKFACE_EPSILON )
return true; // wrong side
}
if( dist >= -BACKFACE_EPSILON )
return true; // wrong side
}
else if( glState.faceCull == GL_BACK )
else
{
if( surf->flags & SURF_PLANEBACK )
{
if( dist <= BACKFACE_EPSILON )
return true; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return true; // wrong side
}
if( dist <= BACKFACE_EPSILON )
return true; // wrong side
}
}
else if( glState.faceCull == GL_BACK )
{
if( surf->flags & SURF_PLANEBACK )
{
if( dist <= BACKFACE_EPSILON )
return true; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return true; // wrong side
}
}
}
}
info = SURF_INFO( surf, RI.currentmodel );
if( frustum )
{
mextrasurf_t *info = SURF_INFO( surf, RI.currentmodel );
return GL_FrustumCullBox( frustum, info->mins, info->maxs, clipflags );
}
return ( clipflags && R_CullBox( info->mins, info->maxs, clipflags ));
return false;
}

355
engine/client/gl_frustum.c Normal file
View File

@ -0,0 +1,355 @@
/*
gl_frustum.cpp - frustum test implementation
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "gl_local.h"
#include "mathlib.h"
void GL_FrustumEnablePlane( gl_frustum_t *out, int side )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
// make sure what plane is ready
if( !VectorIsNull( out->planes[side].normal ))
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumDisablePlane( gl_frustum_t *out, int side )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
ClearBits( out->clipFlags, BIT( side ));
}
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
out->planes[side].type = PlaneTypeForNormal( vecNormal );
out->planes[side].signbits = SignbitsForPlane( vecNormal );
VectorCopy( vecNormal, out->planes[side].normal );
out->planes[side].dist = flDist;
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumNormalizePlane( gl_frustum_t *out, int side )
{
float length;
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
// normalize
length = VectorLength( out->planes[side].normal );
if( length )
{
float ilength = (1.0f / length);
out->planes[side].normal[0] *= ilength;
out->planes[side].normal[1] *= ilength;
out->planes[side].normal[2] *= ilength;
out->planes[side].dist *= ilength;
}
out->planes[side].type = PlaneTypeForNormal( out->planes[side].normal );
out->planes[side].signbits = SignbitsForPlane( out->planes[side].normal );
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY )
{
float xs, xc;
vec3_t farpoint, nearpoint;
vec3_t normal, iforward;
// horizontal fov used for left and right planes
SinCos( DEG2RAD( flFovX ) * 0.5f, &xs, &xc );
// setup left plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, normal, DotProduct( RI.cullorigin, normal ));
// setup right plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, normal, DotProduct( RI.cullorigin, normal ));
// vertical fov used for top and bottom planes
SinCos( DEG2RAD( flFovY ) * 0.5f, &xs, &xc );
VectorNegate( RI.cull_vforward, iforward );
// setup bottom plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, normal, DotProduct( RI.cullorigin, normal ));
// setup top plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_TOP, normal, DotProduct( RI.cullorigin, normal ));
// setup far plane
VectorMA( RI.cullorigin, flZFar, RI.cull_vforward, farpoint );
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, DotProduct( iforward, farpoint ));
// no need to setup backplane for general view. It's only used for portals and mirrors
if( flZNear == 0.0f ) return;
// setup near plane
VectorMA( RI.cullorigin, flZNear, RI.cull_vforward, nearpoint );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, DotProduct( RI.cull_vforward, nearpoint ));
}
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar )
{
vec3_t iforward, iright, iup;
// setup the near and far planes
float orgOffset = DotProduct( RI.cullorigin, RI.cull_vforward );
VectorNegate( RI.cull_vforward, iforward );
// because quake ortho is inverted and far and near should be swaped
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, -flZNear - orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, flZFar + orgOffset );
// setup left and right planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vright );
VectorNegate( RI.cull_vright, iright );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, RI.cull_vright, xLeft + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, iright, -xRight - orgOffset );
// setup top and buttom planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vup );
VectorNegate( RI.cull_vup, iup );
GL_FrustumSetPlane( out, FRUSTUM_TOP, RI.cull_vup, yTop + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, iup, -yBottom - orgOffset );
}
void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius )
{
vec3_t normal;
int i;
for( i = 0; i < FRUSTUM_PLANES; i++ )
{
// setup normal for each direction
VectorClear( normal );
normal[((i >> 1) + 1) % 3] = (i & 1) ? 1.0f : -1.0f;
GL_FrustumSetPlane( out, i, normal, DotProduct( org, normal ) - radius );
}
}
void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection )
{
int i;
// left
out->planes[FRUSTUM_LEFT].normal[0] = projection[0][3] + projection[0][0];
out->planes[FRUSTUM_LEFT].normal[1] = projection[1][3] + projection[1][0];
out->planes[FRUSTUM_LEFT].normal[2] = projection[2][3] + projection[2][0];
out->planes[FRUSTUM_LEFT].dist = -(projection[3][3] + projection[3][0]);
// right
out->planes[FRUSTUM_RIGHT].normal[0] = projection[0][3] - projection[0][0];
out->planes[FRUSTUM_RIGHT].normal[1] = projection[1][3] - projection[1][0];
out->planes[FRUSTUM_RIGHT].normal[2] = projection[2][3] - projection[2][0];
out->planes[FRUSTUM_RIGHT].dist = -(projection[3][3] - projection[3][0]);
// bottom
out->planes[FRUSTUM_BOTTOM].normal[0] = projection[0][3] + projection[0][1];
out->planes[FRUSTUM_BOTTOM].normal[1] = projection[1][3] + projection[1][1];
out->planes[FRUSTUM_BOTTOM].normal[2] = projection[2][3] + projection[2][1];
out->planes[FRUSTUM_BOTTOM].dist = -(projection[3][3] + projection[3][1]);
// top
out->planes[FRUSTUM_TOP].normal[0] = projection[0][3] - projection[0][1];
out->planes[FRUSTUM_TOP].normal[1] = projection[1][3] - projection[1][1];
out->planes[FRUSTUM_TOP].normal[2] = projection[2][3] - projection[2][1];
out->planes[FRUSTUM_TOP].dist = -(projection[3][3] - projection[3][1]);
// near
out->planes[FRUSTUM_NEAR].normal[0] = projection[0][3] + projection[0][2];
out->planes[FRUSTUM_NEAR].normal[1] = projection[1][3] + projection[1][2];
out->planes[FRUSTUM_NEAR].normal[2] = projection[2][3] + projection[2][2];
out->planes[FRUSTUM_NEAR].dist = -(projection[3][3] + projection[3][2]);
// far
out->planes[FRUSTUM_FAR].normal[0] = projection[0][3] - projection[0][2];
out->planes[FRUSTUM_FAR].normal[1] = projection[1][3] - projection[1][2];
out->planes[FRUSTUM_FAR].normal[2] = projection[2][3] - projection[2][2];
out->planes[FRUSTUM_FAR].dist = -(projection[3][3] - projection[3][2]);
for( i = 0; i < FRUSTUM_PLANES; i++ )
{
GL_FrustumNormalizePlane( out, i );
}
}
void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t corners[8] )
{
memset( corners, 0, sizeof( corners ));
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[0] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[1] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[2] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[3] );
if( FBitSet( out->clipFlags, BIT( FRUSTUM_NEAR )))
{
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[4] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[5] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[6] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[7] );
}
else
{
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], corners[4] );
VectorCopy( corners[4], corners[5] );
VectorCopy( corners[4], corners[6] );
VectorCopy( corners[4], corners[7] );
}
}
void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs )
{
vec3_t corners[8];
int i;
GL_FrustumComputeCorners( out, corners );
ClearBounds( mins, maxs );
for( i = 0; i < 8; i++ )
AddPointToBounds( corners[i], mins, maxs );
}
void GL_FrustumDrawDebug( gl_frustum_t *out )
{
vec3_t bbox[8];
int i;
GL_FrustumComputeCorners( out, bbox );
// g-cont. frustum must be yellow :-)
pglColor4f( 1.0f, 1.0f, 0.0f, 1.0f );
pglDisable( GL_TEXTURE_2D );
pglBegin( GL_LINES );
for( i = 0; i < 2; i += 1 )
{
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i*2+0] );
pglVertex3fv( bbox[i*2+1] );
pglVertex3fv( bbox[i*2+4] );
pglVertex3fv( bbox[i*2+5] );
}
pglEnd();
pglEnable( GL_TEXTURE_2D );
}
// cull methods
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull->value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
switch( p->signbits )
{
case 0:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 1:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 2:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 3:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 4:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 5:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 6:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 7:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
default:
return false;
}
}
return false;
}
qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull->value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
if( DotProduct( center, p->normal ) - p->dist <= -radius )
return true;
}
return false;
}

View File

@ -0,0 +1,52 @@
/*
gl_frustum.cpp - frustum test implementation
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_FRUSTUM_H
#define GL_FRUSTUM_H
// don't change this order
#define FRUSTUM_LEFT 0
#define FRUSTUM_RIGHT 1
#define FRUSTUM_BOTTOM 2
#define FRUSTUM_TOP 3
#define FRUSTUM_FAR 4
#define FRUSTUM_NEAR 5
#define FRUSTUM_PLANES 6
typedef struct gl_frustum_s
{
mplane_t planes[FRUSTUM_PLANES];
unsigned int clipFlags;
} gl_frustum_t;
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY );
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar );
void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius ); // used for pointlights
void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection );
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist );
void GL_FrustumNormalizePlane( gl_frustum_t *out, int side );
void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs );
void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t bbox[8] );
void GL_FrustumDrawDebug( gl_frustum_t *out );
// cull methods
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags );
qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t centre, float radius, int userClipFlags );
// plane manipulating
void GL_FrustumEnablePlane( gl_frustum_t *out, int side );
void GL_FrustumDisablePlane( gl_frustum_t *out, int side );
#endif//GL_FRUSTUM_H

View File

@ -22,6 +22,7 @@ GNU General Public License for more details.
#include "render_api.h"
#include "protocol.h"
#include "dlight.h"
#include "gl_frustum.h"
extern byte *r_temppool;
@ -112,7 +113,7 @@ typedef struct
cl_entity_t *currentbeam; // same as above but for beams
int viewport[4];
mplane_t frustum[6];
gl_frustum_t frustum;
mleaf_t *viewleaf;
mleaf_t *oldviewleaf;
@ -129,7 +130,6 @@ typedef struct
vec3_t cull_vup;
float farClip;
uint clipFlags;
qboolean fogCustom;
qboolean fogEnabled;
@ -277,9 +277,9 @@ void R_ShowTextures( void );
// gl_cull.c
//
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs, uint clipflags );
qboolean R_CullSphere( const vec3_t centre, const float radius, const uint clipflags );
qboolean R_CullSurface( msurface_t *surf, uint clipflags );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
qboolean R_CullSphere( const vec3_t centre, const float radius );
qboolean R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags );
//
// gl_decals.c
@ -352,8 +352,11 @@ void R_ClearScene( void );
void R_LoadIdentity( void );
void R_RenderScene( void );
void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size );
void R_SetupRefParams( const struct ref_viewpass_s *rvp );
qboolean R_StaticEntity( cl_entity_t *ent );
void R_TranslateForEntity( cl_entity_t *e );
void R_RotateForEntity( cl_entity_t *e );
void R_SetupGL( qboolean set_gl_state );
qboolean R_InitRenderAPI( void );
void R_SetupFrustum( void );
void R_FindViewLeaf( void );
@ -465,7 +468,7 @@ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, c
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
qboolean R_SpeedsMessage( char *out, size_t size );
void R_SetupSky( const char *skyboxname );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs, uint clipflags );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
qboolean R_WorldToScreen( const vec3_t point, vec3_t screen );
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );

View File

@ -263,13 +263,9 @@ void R_DrawMirrors( void )
angles[ROLL] = -angles[ROLL];
RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF;
RI.clipPlane = plane;
RI.clipFlags |= ( 1<<5 );
RI.frustum[5] = plane;
RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal );
RI.frustum[5].type = PLANE_NONAXIAL;
GL_FrustumSetPlane( &RI.frustum, FRUSTUM_NEAR, plane.normal, plane.dist );
RI.viewangles[0] = anglemod( angles[0] );
RI.viewangles[1] = anglemod( angles[1] );
@ -348,7 +344,6 @@ R_RecursiveMirrorNode
void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
{
mextrasurf_t *extrasurf;
const mplane_t *clipplane;
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
@ -363,14 +358,16 @@ void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
if( clipflags )
{
for( i = 0, clipplane = RI.frustum; i < 6; i++, clipplane++ )
for( i = 0; i < 6; i++ )
{
if(!( clipflags & ( 1<<i )))
const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i )))
continue;
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, clipplane );
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return;
if( clipped == 1 ) clipflags &= ~(1<<i);
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
}
}
@ -408,7 +405,7 @@ void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
if(!( surf->flags & SURF_REFLECT ))
continue;
if( R_CullSurface( surf, clipflags ))
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
extrasurf = SURF_INFO( surf, RI.currentmodel );
@ -434,19 +431,24 @@ void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
msurface_t *psurf;
model_t *clmodel;
qboolean rotated;
int i, clipFlags;
gl_frustum_t *frustum = NULL;
int i;
clmodel = e->model;
// don't draw any water reflections if we underwater
if( cl.local.waterlevel >= 3 && FBitSet( clmodel->flags, MODEL_LIQUID ))
return;
if( static_entity )
{
Matrix4x4_LoadIdentity( RI.objectMatrix );
if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags ))
if( R_CullBox( clmodel->mins, clmodel->maxs ))
return;
VectorCopy( RI.cullorigin, tr.modelorg );
clipFlags = RI.clipFlags;
frustum = &RI.frustum;
}
else
{
@ -466,7 +468,7 @@ void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
rotated = false;
}
if( R_CullBox( mins, maxs, RI.clipFlags ))
if( R_CullBox( mins, maxs ))
return;
if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles ))
@ -480,17 +482,15 @@ void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );
clipFlags = 0;
}
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
{
if(!( psurf->flags & SURF_REFLECT ))
if( !FBitSet( psurf->flags, SURF_REFLECT ))
continue;
if( R_CullSurface( psurf, clipFlags ))
if( R_CullSurface( psurf, frustum, 0 ))
continue;
extrasurf = SURF_INFO( psurf, RI.currentmodel );
@ -590,16 +590,20 @@ void R_FindMirrors( void )
// NOTE: we already has initial params at this point like vieworg, viewangles
// all other will be sets into R_SetupFrustum
R_FindViewLeaf ();
// player is outside world. Don't update mirrors for speedup reasons
if(( RI.viewleaf - cl.worldmodel->leafs - 1 ) == -1 )
return;
R_SetupFrustum ();
R_FindViewLeaf ();
R_MarkLeaves ();
VectorCopy( RI.cullorigin, tr.modelorg );
RI.currententity = clgame.entities;
RI.currentmodel = RI.currententity->model;
R_RecursiveMirrorNode( cl.worldmodel->nodes, RI.clipFlags );
R_RecursiveMirrorNode( cl.worldmodel->nodes, RI.frustum.clipFlags );
R_CheckEntitiesOnList();
}

View File

@ -171,7 +171,7 @@ void R_PushDlights( void )
if( l->die < cl.time || !l->radius )
continue;
if( R_CullSphere( l->origin, l->radius, 15 ))
if( GL_FrustumCullSphere( &RI.frustum, l->origin, l->radius, 15 ))
continue;
R_MarkLights( l, 1<<i, RI.currentmodel->nodes );

View File

@ -51,7 +51,7 @@ Static entity is the brush which has no custom origin and not rotated
typically is a func_wall, func_breakable, func_ladder etc
===============
*/
static qboolean R_StaticEntity( cl_entity_t *ent )
qboolean R_StaticEntity( cl_entity_t *ent )
{
if( !gl_allow_static->value )
return false;
@ -354,55 +354,6 @@ static float R_GetFarClip( void )
return 2048.0f;
}
/*
===============
R_SetupFrustumOrtho
===============
*/
static void R_SetupFrustumOrtho( void )
{
ref_overview_t *ov = &clgame.overView;
float orgOffset;
int i;
// 0 - left
// 1 - right
// 2 - down
// 3 - up
// 4 - farclip
// 5 - nearclip
// setup the near and far planes.
orgOffset = DotProduct( RI.cullorigin, RI.cull_vforward );
VectorNegate( RI.cull_vforward, RI.frustum[4].normal );
RI.frustum[4].dist = -ov->zFar - orgOffset;
VectorCopy( RI.cull_vforward, RI.frustum[5].normal );
RI.frustum[5].dist = ov->zNear + orgOffset;
// left and right planes...
orgOffset = DotProduct( RI.cullorigin, RI.cull_vright );
VectorCopy( RI.cull_vright, RI.frustum[0].normal );
RI.frustum[0].dist = ov->xLeft + orgOffset;
VectorNegate( RI.cull_vright, RI.frustum[1].normal );
RI.frustum[1].dist = -ov->xRight - orgOffset;
// top and buttom planes...
orgOffset = DotProduct( RI.cullorigin, RI.cull_vup );
VectorCopy( RI.cull_vup, RI.frustum[3].normal );
RI.frustum[3].dist = ov->xTop + orgOffset;
VectorNegate( RI.cull_vup, RI.frustum[2].normal );
RI.frustum[2].dist = -ov->xBottom - orgOffset;
for( i = 0; i < 6; i++ )
{
RI.frustum[i].type = PLANE_NONAXIAL;
RI.frustum[i].signbits = SignbitsForPlane( RI.frustum[i].normal );
}
}
/*
===============
R_SetupFrustum
@ -410,8 +361,7 @@ R_SetupFrustum
*/
void R_SetupFrustum( void )
{
vec3_t farPoint;
int i;
ref_overview_t *ov = &clgame.overView;
// build the transformation matrix for the given view angles
AngleVectors( RI.viewangles, RI.vforward, RI.vright, RI.vup );
@ -425,40 +375,8 @@ void R_SetupFrustum( void )
}
if( RI.drawOrtho )
{
R_SetupFrustumOrtho();
return;
}
// 0 - left
// 1 - right
// 2 - down
// 3 - up
// 4 - farclip
// 5 - nearclip
// rotate RI.vforward right by FOV_X/2 degrees
RotatePointAroundVector( RI.frustum[0].normal, RI.cull_vup, RI.cull_vforward, -( 90 - RI.fov_x / 2 ));
// rotate RI.vforward left by FOV_X/2 degrees
RotatePointAroundVector( RI.frustum[1].normal, RI.cull_vup, RI.cull_vforward, 90 - RI.fov_x / 2 );
// rotate RI.vforward up by FOV_X/2 degrees
RotatePointAroundVector( RI.frustum[2].normal, RI.cull_vright, RI.cull_vforward, 90 - RI.fov_y / 2 );
// rotate RI.vforward down by FOV_X/2 degrees
RotatePointAroundVector( RI.frustum[3].normal, RI.cull_vright, RI.cull_vforward, -( 90 - RI.fov_y / 2 ));
// negate forward vector
VectorNegate( RI.cull_vforward, RI.frustum[4].normal );
for( i = 0; i < 4; i++ )
{
RI.frustum[i].type = PLANE_NONAXIAL;
RI.frustum[i].dist = DotProduct( RI.cullorigin, RI.frustum[i].normal );
RI.frustum[i].signbits = SignbitsForPlane( RI.frustum[i].normal );
}
VectorMA( RI.cullorigin, R_GetFarClip(), RI.cull_vforward, farPoint );
RI.frustum[i].type = PLANE_NONAXIAL;
RI.frustum[i].dist = DotProduct( farPoint, RI.frustum[i].normal );
RI.frustum[i].signbits = SignbitsForPlane( RI.frustum[i].normal );
GL_FrustumInitOrtho( &RI.frustum, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
else GL_FrustumInitProj( &RI.frustum, 0.0f, R_GetFarClip(), RI.fov_x, RI.fov_y ); // NOTE: we ignore nearplane here (mirrors only)
}
/*
@ -473,8 +391,7 @@ static void R_SetupProjectionMatrix( matrix4x4 m )
if( RI.drawOrtho )
{
ref_overview_t *ov = &clgame.overView;
Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->xTop, ov->xBottom, ov->zNear, ov->zFar );
RI.clipFlags = 0;
Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
return;
}
@ -623,7 +540,7 @@ static void R_SetupFrame( void )
R_SetupGL
=============
*/
static void R_SetupGL( void )
void R_SetupGL( qboolean set_gl_state )
{
if( RP_NORMALPASS() && ( cl.local.waterlevel >= 3 ))
{
@ -633,10 +550,11 @@ static void R_SetupGL( void )
R_SetupModelviewMatrix( RI.worldviewMatrix );
R_SetupProjectionMatrix( RI.projectionMatrix );
// if( RI.params & RP_MIRRORVIEW ) RI.projectionMatrix[0][0] = -RI.projectionMatrix[0][0];
Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix );
if( !set_gl_state ) return;
if( RP_NORMALPASS( ))
{
int x, x2, y, y2;
@ -1001,7 +919,7 @@ void R_RenderScene( void )
R_SetupFrustum();
R_SetupFrame();
R_SetupGL();
R_SetupGL( true );
R_Clear( ~0 );
R_MarkLeaves();
@ -1112,7 +1030,6 @@ void R_SetupRefParams( const ref_viewpass_t *rvp )
RI.params = RP_NONE;
RI.drawWorld = FBitSet( rvp->flags, RF_DRAW_WORLD );
RI.onlyClientDraw = FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW );
RI.clipFlags = 15; // top, bottom, left, right
RI.farClip = 0;
if( !FBitSet( rvp->flags, RF_DRAW_CUBEMAP ))

View File

@ -528,7 +528,7 @@ static qboolean CL_CullTracer( particle_t *p, const vec3_t start, const vec3_t e
}
// check bbox
return R_CullBox( mins, maxs, RI.clipFlags );
return R_CullBox( mins, maxs );
}
/*
@ -648,17 +648,35 @@ void CL_DrawTracers( double frametime )
}
}
void CL_DrawParticlesExternal( const float *vieworg, const float *forward, const float *right, const float *up, uint clipFlags )
/*
===============
CL_DrawParticlesExternal
allow to draw effects from custom renderer
===============
*/
void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean solid_pass )
{
if( vieworg ) VectorCopy( vieworg, RI.vieworg );
if( forward ) VectorCopy( forward, RI.vforward );
if( right ) VectorCopy( right, RI.vright );
if( up ) VectorCopy( up, RI.vup );
ref_instance_t oldRI = RI;
RI.clipFlags = clipFlags;
memcpy( &oldRI, &RI, sizeof( ref_instance_t ));
R_SetupRefParams( rvp );
R_SetupFrustum();
R_SetupGL( false ); // don't touch GL-states
CL_DrawParticles ( tr.frametime );
CL_DrawTracers( tr.frametime );
if( solid_pass )
{
CL_DrawBeams( false );
}
else
{
CL_DrawBeams( true );
CL_DrawParticles( tr.frametime );
CL_DrawTracers( tr.frametime );
}
// restore internal state
memcpy( &RI, &oldRI, sizeof( ref_instance_t ));
}
/*

View File

@ -1442,7 +1442,7 @@ void R_DrawBrushModel( cl_entity_t *e )
rotated = false;
}
if( R_CullBox( mins, maxs, RI.clipFlags ))
if( R_CullBox( mins, maxs ))
return;
memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces ));
@ -1505,7 +1505,7 @@ void R_DrawBrushModel( cl_entity_t *e )
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
{
if( R_CullSurface( psurf, 0 ))
if( R_CullSurface( psurf, NULL, 0 )) // ignore frustum for bmodels
continue;
if( need_sort && !gl_nosort->value )
@ -1561,7 +1561,7 @@ void R_DrawStaticModel( cl_entity_t *e )
dlight_t *l;
clmodel = e->model;
if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags ))
if( R_CullBox( clmodel->mins, clmodel->maxs ))
return;
// calculate dynamic lighting for bmodel
@ -1575,7 +1575,7 @@ void R_DrawStaticModel( cl_entity_t *e )
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
{
if( R_CullSurface( psurf, RI.clipFlags ))
if( R_CullSurface( psurf, &RI.frustum, 0 ))
continue;
if( psurf->flags & SURF_DRAWSKY )
@ -1638,7 +1638,6 @@ R_RecursiveWorldNode
*/
void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
{
const mplane_t *clipplane;
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
@ -1653,14 +1652,16 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
if( clipflags )
{
for( i = 0, clipplane = RI.frustum; i < 6; i++, clipplane++ )
for( i = 0; i < 6; i++ )
{
if(!( clipflags & ( 1<<i )))
const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i )))
continue;
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, clipplane );
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return;
if( clipped == 1 ) clipflags &= ~(1<<i);
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
}
}
@ -1701,7 +1702,7 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
// draw stuff
for( c = node->numsurfaces, surf = cl.worldmodel->surfaces + node->firstsurface; c; c--, surf++ )
{
if( R_CullSurface( surf, clipflags ))
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
if( surf->flags & SURF_DRAWSKY )
@ -1764,7 +1765,7 @@ static void R_DrawTopViewLeaf( mleaf_t *pleaf, uint clipflags )
surf->visframe = tr.framecount;
if( R_CullSurface( surf, clipflags ))
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
if(!( surf->flags & SURF_DRAWSKY ))
@ -1788,8 +1789,7 @@ R_DrawWorldTopView
*/
void R_DrawWorldTopView( mnode_t *node, uint clipflags )
{
const mplane_t *clipplane;
int c, clipped;
int i, c, clipped;
msurface_t *surf;
do
@ -1802,14 +1802,16 @@ void R_DrawWorldTopView( mnode_t *node, uint clipflags )
if( clipflags )
{
for( c = 0, clipplane = RI.frustum; c < 6; c++, clipplane++ )
for( i = 0; i < 6; i++ )
{
if(!( clipflags & ( 1<<c )))
const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i )))
continue;
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, clipplane );
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return;
if( clipped == 1 ) clipflags &= ~(1<<c);
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
}
}
@ -1833,7 +1835,7 @@ void R_DrawWorldTopView( mnode_t *node, uint clipflags )
surf->visframe = tr.framecount;
if( R_CullSurface( surf, clipflags ))
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
if(!( surf->flags & SURF_DRAWSKY ))
@ -1938,11 +1940,11 @@ void R_DrawWorld( void )
if( RI.drawOrtho )
{
R_DrawWorldTopView( cl.worldmodel->nodes, RI.clipFlags );
R_DrawWorldTopView( cl.worldmodel->nodes, RI.frustum.clipFlags );
}
else
{
R_RecursiveWorldNode( cl.worldmodel->nodes, RI.clipFlags );
R_RecursiveWorldNode( cl.worldmodel->nodes, RI.frustum.clipFlags );
}
R_DrawStaticBrushes();

View File

@ -1599,7 +1599,7 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight )
int sequence = bound( 0, ent->curstate.sequence, m_pStudioHeader->numseq - 1 );
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + sequence;
if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING ) && !pseqdesc->activity )
if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING ) && !pseqdesc->activity && m_pStudioHeader->numseq > 1 )
Matrix3x4_OriginFromMatrix( g_studio.lighttransform[0], origin );
else Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, origin );
}
@ -2650,14 +2650,14 @@ static void R_StudioClientEvents( void )
if( pseqdesc->numevents == 0 )
return;
end = R_StudioEstimateFrame( e, pseqdesc ) + 0.01f;
end = R_StudioEstimateFrame( e, pseqdesc );
start = end - e->curstate.framerate * host.frametime * pseqdesc->fps;
pevent = (mstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex);
if( e->latched.sequencetime == e->curstate.animtime )
{
if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING ))
start -= 0.01f;
start = -0.01f;
}
for( i = 0; i < pseqdesc->numevents; i++ )
@ -2666,7 +2666,7 @@ static void R_StudioClientEvents( void )
if( pevent[i].event < EVENT_CLIENT )
continue;
if( (float)pevent[i].frame > start && end >= pevent[i].frame )
if( (float)pevent[i].frame > start && pevent[i].frame <= end )
clgame.dllFuncs.pfnStudioEvent( &pevent[i], e );
}
}

View File

@ -157,6 +157,65 @@ int SignbitsForPlane( const vec3_t normal )
return bits;
}
/*
=================
PlaneTypeForNormal
=================
*/
int PlaneTypeForNormal( const vec3_t normal )
{
if( normal[0] == 1.0f )
return PLANE_X;
if( normal[1] == 1.0f )
return PLANE_Y;
if( normal[2] == 1.0f )
return PLANE_Z;
return PLANE_NONAXIAL;
}
/*
=================
PlanesGetIntersectionPoint
=================
*/
qboolean PlanesGetIntersectionPoint( const mplane_t *plane1, const mplane_t *plane2, const mplane_t *plane3, vec3_t out )
{
vec3_t n1, n2, n3;
vec3_t n1n2, n2n3, n3n1;
float denom;
VectorNormalize2( plane1->normal, n1 );
VectorNormalize2( plane2->normal, n2 );
VectorNormalize2( plane3->normal, n3 );
CrossProduct( n1, n2, n1n2 );
CrossProduct( n2, n3, n2n3 );
CrossProduct( n3, n1, n3n1 );
denom = DotProduct( n1, n2n3 );
VectorClear( out );
// check if the denominator is zero (which would mean that no intersection is to be found
if( denom == 0.0f )
{
// no intersection could be found, return <0,0,0>
return false;
}
// compute intersection point
#if 0
VectorMAMAM( plane1->dist, n2n3, plane2->dist, n3n1, plane3->dist, n1n2, out );
#else
VectorMA( out, plane1->dist, n2n3, out );
VectorMA( out, plane2->dist, n3n1, out );
VectorMA( out, plane3->dist, n1n2, out );
#endif
VectorScale( out, ( 1.0f / denom ), out );
return true;
}
/*
=================
NearestPOW
@ -408,6 +467,21 @@ void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs )
}
}
/*
=================
ExpandBounds
=================
*/
void ExpandBounds( vec3_t mins, vec3_t maxs, float offset )
{
mins[0] -= offset;
mins[1] -= offset;
mins[2] -= offset;
maxs[0] += offset;
maxs[1] += offset;
maxs[2] += offset;
}
/*
=================
BoundsIntersect
@ -459,6 +533,23 @@ qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared
return true;
}
/*
=================
PlaneIntersect
find point where ray
was intersect with plane
=================
*/
void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, vec3_t out )
{
float distToPlane = PlaneDiff( p0, plane );
float planeDotRay = DotProduct( plane->normal, p1 );
float sect = -(distToPlane) / planeDotRay;
VectorMA( p0, sect, p1, out );
}
/*
=================
RadiusFromBounds
@ -476,41 +567,6 @@ float RadiusFromBounds( const vec3_t mins, const vec3_t maxs )
return VectorLength( corner );
}
/*
====================
RotatePointAroundVector
====================
*/
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
{
float t0, t1;
float angle, c, s;
vec3_t vr, vu, vf;
angle = DEG2RAD( degrees );
SinCos( angle, &s, &c );
VectorCopy( dir, vf );
VectorVectors( vf, vr, vu );
t0 = vr[0] * c + vu[0] * -s;
t1 = vr[0] * s + vu[0] * c;
dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0]
+ (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1]
+ (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2];
t0 = vr[1] * c + vu[1] * -s;
t1 = vr[1] * s + vu[1] * c;
dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0]
+ (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1]
+ (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2];
t0 = vr[2] * c + vu[2] * -s;
t1 = vr[2] * s + vu[2] * c;
dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0]
+ (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1]
+ (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2];
}
//
// studio utils
//

View File

@ -108,6 +108,7 @@ GNU General Public License for more details.
#define VectorNegate(x, y) ((y)[0] = -(x)[0], (y)[1] = -(x)[1], (y)[2] = -(x)[2])
#define VectorM(scale1, b1, c) ((c)[0] = (scale1) * (b1)[0],(c)[1] = (scale1) * (b1)[1],(c)[2] = (scale1) * (b1)[2])
#define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2])
#define VectorMAM(scale1, b1, scale2, b2, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2])
#define VectorMAMAM(scale1, b1, scale2, b2, scale3, b3, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2])
#define VectorIsNull( v ) ((v)[0] == 0.0f && (v)[1] == 0.0f && (v)[2] == 0.0f)
#define MakeRGBA( out, x, y, z, w ) Vector4Set( out, x, y, z, w )
@ -121,6 +122,7 @@ word FloatToHalf( float v );
float HalfToFloat( word h );
void RoundUpHullSize( vec3_t size );
int SignbitsForPlane( const vec3_t normal );
int PlaneTypeForNormal( const vec3_t normal );
int NearestPOW( int value, qboolean roundDown );
void SinCos( float radians, float *sine, float *cosine );
float VectorNormalizeLength2( const vec3_t v, vec3_t out );
@ -128,7 +130,8 @@ void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up );
void VectorAngles( const float *forward, float *angles );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up );
void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, vec3_t angles );
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
qboolean PlanesGetIntersectionPoint( const struct mplane_s *plane1, const struct mplane_s *plane2, const struct mplane_s *plane3, vec3_t out );
void PlaneIntersect( const struct mplane_s *plane, const vec3_t p0, const vec3_t p1, vec3_t out );
void ClearBounds( vec3_t mins, vec3_t maxs );
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
@ -136,6 +139,7 @@ qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t m
qboolean BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t origin, float radius );
qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared, const vec3_t vLinePt, const vec3_t vLineDir );
float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
void ExpandBounds( vec3_t mins, vec3_t maxs, float offset );
void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio );
void QuaternionAngle( const vec4_t q, vec3_t angles );

View File

@ -260,6 +260,10 @@ SOURCE=.\client\gl_draw.c
# End Source File
# Begin Source File
SOURCE=.\client\gl_frustum.c
# End Source File
# Begin Source File
SOURCE=.\client\gl_image.c
# End Source File
# Begin Source File
@ -588,6 +592,10 @@ SOURCE=.\client\gl_export.h
# End Source File
# Begin Source File
SOURCE=.\client\gl_frustum.h
# End Source File
# Begin Source File
SOURCE=.\client\gl_local.h
# End Source File
# Begin Source File

View File

@ -16,15 +16,15 @@ GNU General Public License for more details.
#ifndef PHYSINT_H
#define PHYSINT_H
#define SV_PHYSICS_INTERFACE_VERSION 6
#define SV_PHYSICS_INTERFACE_VERSION 6
#define STRUCT_FROM_LINK( l, t, m ) ((t *)((byte *)l - (int)&(((t *)0)->m)))
#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area )
#define STRUCT_FROM_LINK( l, t, m ) ((t *)((byte *)l - (int)&(((t *)0)->m)))
#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area )
// values that can be returned with pfnServerState
#define SERVER_DEAD 0
#define SERVER_LOADING 1
#define SERVER_ACTIVE 2
#define SERVER_DEAD 0
#define SERVER_LOADING 1
#define SERVER_ACTIVE 2
// LUMP reading errors
#define LUMP_LOAD_OK 0
@ -55,7 +55,6 @@ typedef struct areanode_s
struct areanode_s *children[2];
link_t trigger_edicts;
link_t solid_edicts;
link_t water_edicts; // func water
} areanode_t;
typedef struct server_physics_api_s
@ -65,7 +64,7 @@ typedef struct server_physics_api_s
double ( *pfnGetServerTime )( void ); // unclamped
double ( *pfnGetFrameTime )( void ); // unclamped
void* ( *pfnGetModel )( int modelindex );
areanode_t* ( *pfnGetHeadnode )( void ); // BSP tree for all physic entities
areanode_t* ( *pfnGetHeadnode )( void ); // AABB tree for all physic entities
int ( *pfnServerState )( void );
void ( *pfnHost_Error )( const char *error, ... ); // cause Host Error
// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 6
@ -111,7 +110,7 @@ typedef struct physics_interface_s
{
int version;
// passed through pfnCreate (0 is attempt to create, -1 is reject)
int ( *SV_CreateEntity )( edict_t *pent, const char *szName );
int ( *SV_CreateEntity )( edict_t *pent, const char *szName );
// run custom physics for each entity (return 0 to use built-in engine physic)
int ( *SV_PhysicsEntity )( edict_t *pEntity );
// spawn entities with internal mod function e.g. for re-arrange spawn order (0 - use engine parser, 1 - use mod parser)
@ -153,6 +152,8 @@ typedef struct physics_interface_s
void (*PM_PlayerTouch)( struct playermove_s *ppmove, edict_t *client );
// alloc or destroy model custom data (called only for dedicated servers, otherwise using an client version)
void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer );
// select BSP-hull for trace with specified mins\maxs
void *(*SV_HullForBsp)( edict_t *ent, const vec3_t mins, const vec3_t maxs, vec3_t offset );
} physics_interface_t;
#endif//PHYSINT_H

View File

@ -430,7 +430,6 @@ extern convar_t *sv_novis;
extern convar_t *sv_allow_studio_attachment_angles;
extern convar_t *sv_allow_rotate_pushables;
extern convar_t *sv_sendvelocity;
extern convar_t *sv_quakehulls;
extern convar_t *sv_validate_changelevel;
extern convar_t *public_server;
@ -575,6 +574,7 @@ char *SV_ReadEntityScript( const char *filename, int *flags );
float SV_AngleMod( float ideal, float current, float speed );
void SV_SpawnEntities( const char *mapname, char *entities );
edict_t* SV_AllocPrivateData( edict_t *ent, string_t className );
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className );
string_t SV_AllocString( const char *szValue );
string_t SV_MakeString( const char *szValue );
const char *SV_GetString( string_t iString );

View File

@ -863,6 +863,12 @@ edict_t *SV_AllocEdict( void )
return pEdict;
}
LINK_ENTITY_FUNC SV_GetEntityClass( const char *pszClassName )
{
// allocate edict private memory (passed by dlls)
return (LINK_ENTITY_FUNC)Com_GetProcAddress( svgame.hInstance, pszClassName );
}
edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
{
const char *pszClassName;
@ -885,7 +891,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
ent->v.pContainingEntity = ent; // re-link
// allocate edict private memory (passed by dlls)
SpawnEdict = (LINK_ENTITY_FUNC)Com_GetProcAddress( svgame.hInstance, pszClassName );
SpawnEdict = SV_GetEntityClass( pszClassName );
if( !SpawnEdict )
{
@ -893,18 +899,35 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
return ent;
MsgDev( D_ERROR, "No spawn function for %s\n", STRING( className ));
SpawnEdict = SV_GetEntityClass( "custom" );
// kill entity immediately
SV_FreeEdict( ent );
if( !SpawnEdict )
{
MsgDev( D_ERROR, "No spawn function for %s\n", STRING( className ));
return NULL;
// kill entity immediately
SV_FreeEdict( ent );
return NULL;
}
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // sort of hack
}
else SpawnEdict( &ent->v );
SpawnEdict( &ent->v );
return ent;
}
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
{
edict_t *ed = SV_AllocPrivateData( ent, className );
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
return ed;
}
void SV_FreeEdicts( void )
{
int i = 0;
@ -1613,7 +1636,7 @@ pfnCreateNamedEntity
*/
edict_t* pfnCreateNamedEntity( string_t className )
{
return SV_AllocPrivateData( NULL, className );
return SV_CreateNamedEntity( NULL, className );
}
/*
@ -4527,7 +4550,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
{
KeyValueData pkvd[256]; // per one entity
int i, numpairs = 0;
const char *classname = NULL;
char *classname = NULL;
char token[2048];
// go through all the dictionary pairs
@ -4565,19 +4588,19 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( !token[0] ) continue;
// create keyvalue strings
pkvd[numpairs].szClassName = (char *)classname; // unknown at this moment
pkvd[numpairs].szClassName = ""; // unknown at this moment
pkvd[numpairs].szKeyName = copystring( keyname );
pkvd[numpairs].szValue = copystring( token );
pkvd[numpairs].fHandled = false;
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
classname = pkvd[numpairs].szValue;
classname = copystring( pkvd[numpairs].szValue );
if( ++numpairs >= 256 ) break;
}
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname ));
if( !SV_IsValidEdict( ent ) || ent->v.flags & FL_KILLME )
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
{
// release allocated strings
for( i = 0; i < numpairs; i++ )
@ -4588,6 +4611,19 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
return false;
}
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
{
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
if( numpairs < 256 )
{
pkvd[numpairs].szClassName = "custom";
pkvd[numpairs].szKeyName = "customclass";
pkvd[numpairs].szValue = classname;
pkvd[numpairs].fHandled = false;
numpairs++;
}
}
for( i = 0; i < numpairs; i++ )
{
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
@ -4615,7 +4651,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( !pkvd[i].fHandled )
{
pkvd[i].szClassName = (char *)classname;
pkvd[i].szClassName = classname;
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
}
@ -4624,6 +4660,9 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
Mem_Free( pkvd[i].szValue );
}
if( classname )
Mem_Free( classname );
return true;
}

View File

@ -117,7 +117,6 @@ convar_t *sv_allow_studio_attachment_angles;
convar_t *sv_allow_rotate_pushables;
convar_t *sv_validate_changelevel;
convar_t *sv_sendvelocity;
convar_t *sv_quakehulls;
void Master_Shutdown( void );
@ -776,7 +775,6 @@ void SV_Init( void )
Cvar_RegisterVariable (&sv_send_logos);
Cvar_RegisterVariable (&sv_send_resources);
sv_sendvelocity = Cvar_Get( "sv_sendvelocity", "1", FCVAR_ARCHIVE, "force to send velocity for event_t structure across network" );
sv_quakehulls = Cvar_Get( "sv_quakehulls", "0", FCVAR_ARCHIVE, "using quake style hull select instead of half-life style hull select" );
Cvar_RegisterVariable (&sv_consistency);
sv_novis = Cvar_Get( "sv_novis", "0", 0, "force to ignore server visibility" );

View File

@ -201,7 +201,7 @@ qboolean SV_RunThink( edict_t *ent )
if( !FBitSet( ent->v.flags, FL_KILLME ))
{
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > sv.time + sv.frametime )
if( thinktime <= 0.0f || thinktime > (sv.time + sv.frametime))
return true;
if( thinktime < sv.time )
@ -236,7 +236,7 @@ qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time )
if( !FBitSet( ent->v.flags, FL_KILLME|FL_DORMANT ))
{
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || (time + frametime) < thinktime )
if( thinktime <= 0.0f || thinktime > (time + frametime))
return true;
if( thinktime < time )

View File

@ -67,8 +67,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
if( ed->v.flags & FL_CLIENT )
{
// client
if( svs.currentPlayer )
SV_GetTrueOrigin( svs.currentPlayer, (pe->info - 1), pe->origin );
SV_GetTrueOrigin( &svs.clients[pe->info - 1], (pe->info - 1), pe->origin );
Q_strncpy( pe->name, "player", sizeof( pe->name ));
pe->player = pe->info;
}
@ -148,15 +147,15 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
{
if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag.value )
return;
// don't allow unlag in singleplayer
if( svs.maxclients <= 1 ) return;
if( cl->state < cs_connected || edictnum < 0 || edictnum >= svs.maxclients )
return;
if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag.value )
return;
if( !svgame.interp[edictnum].active || !svgame.interp[edictnum].moving )
return;
@ -165,15 +164,15 @@ void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs )
{
if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag.value )
return;
// don't allow unlag in singleplayer
if( svs.maxclients <= 1 ) return;
if( cl->state < cs_connected || edictnum < 0 || edictnum >= svs.maxclients )
return;
if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag.value )
return;
if( !svgame.interp[edictnum].active || !svgame.interp[edictnum].moving )
return;
@ -241,9 +240,10 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
if( FBitSet( check->v.flags, FL_CLIENT ))
{
int e = NUM_FOR_EDICT( check ) - 1;
// trying to get interpolated values
if( svs.currentPlayer )
SV_GetTrueMinMax( svs.currentPlayer, ( NUM_FOR_EDICT( check ) - 1), mins, maxs );
SV_GetTrueMinMax( &svs.clients[e], e, mins, maxs );
}
if( !BoundsIntersect( pmove_mins, pmove_maxs, mins, maxs ))
@ -279,12 +279,12 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3
physent_t *pe;
// get water edicts
for( l = node->water_edicts.next; l != &node->water_edicts; l = next )
for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
{
next = l->next;
check = EDICT_FROM_AREA( l );
if( check->v.solid != SOLID_NOT ) // disabled ?
if( check->v.solid != SOLID_NOT || check->v.skin != CONTENTS_LADDER )
continue;
// only brushes can have special contents

View File

@ -1574,7 +1574,7 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
pent = EDICT_NUM( 0 );
SV_InitEdict( pent );
pent = SV_AllocPrivateData( pent, pEntInfo->classname );
pent = SV_CreateNamedEntity( pent, pEntInfo->classname );
}
else if(( pEntInfo->id > 0 ) && ( pEntInfo->id < svgame.globals->maxClients + 1 ))
{
@ -1592,13 +1592,13 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
{
ASSERT( ed->free == false );
// create the player
pent = SV_AllocPrivateData( ed, pEntInfo->classname );
pent = SV_CreateNamedEntity( ed, pEntInfo->classname );
}
else pent = NULL;
}
else
{
pent = SV_AllocPrivateData( NULL, pEntInfo->classname );
pent = SV_CreateNamedEntity( NULL, pEntInfo->classname );
}
pEntInfo->pent = pent;
@ -1706,13 +1706,13 @@ int SV_CreateEntityTransitionList( SAVERESTOREDATA *pSaveData, int levelMask )
ASSERT( 0 );
}
pent = SV_AllocPrivateData( ed, pEntInfo->classname );
pent = SV_CreateNamedEntity( ed, pEntInfo->classname );
}
}
else if( active )
{
// create named entity
pent = SV_AllocPrivateData( NULL, pEntInfo->classname );
pent = SV_CreateNamedEntity( NULL, pEntInfo->classname );
}
}
else

View File

@ -216,12 +216,18 @@ SV_HullForBsp
forcing to select BSP hull
==================
*/
hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float *offset )
hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, vec3_t offset )
{
hull_t *hull;
model_t *model;
vec3_t size;
if( svgame.physFuncs.SV_HullForBsp != NULL )
{
hull = svgame.physFuncs.SV_HullForBsp( ent, mins, maxs, offset );
if( hull ) return hull;
}
// decide which clipping hull to use, based on the size
model = Mod_Handle( ent->v.modelindex );
@ -234,7 +240,8 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float
// author: The FiEctro
hull = &model->hulls[COM_RandomLong( 0, 0 )];
#endif
if( sv_quakehulls->value == 1 )
if( world.sky_sphere || world.version == Q1BSP_VERSION )
{
// Using quake-style hull select for my Quake remake
if( size[0] < 3.0f || ( model->flags & MODEL_LIQUID && ent->v.solid != SOLID_TRIGGER ))
@ -245,11 +252,6 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, float
VectorSubtract( hull->clip_mins, mins, offset );
}
else if( sv_quakehulls->value == 2 )
{
// undocumented feature: auto hull select
hull = SV_HullAutoSelect( model, mins, maxs, size, offset );
}
else
{
if( size[0] <= 8.0f || ( model->flags & MODEL_LIQUID && ent->v.solid != SOLID_TRIGGER ))
@ -421,7 +423,6 @@ areanode_t *SV_CreateAreaNode( int depth, vec3_t mins, vec3_t maxs )
ClearLink( &anode->trigger_edicts );
ClearLink( &anode->solid_edicts );
ClearLink( &anode->water_edicts );
if( depth == AREA_DEPTH )
{
@ -676,8 +677,6 @@ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
// link it in
if( ent->v.solid == SOLID_TRIGGER )
InsertLinkBefore( &ent->area, &node->trigger_edicts );
else if( ent->v.solid == SOLID_NOT && ent->v.skin < CONTENTS_EMPTY )
InsertLinkBefore( &ent->area, &node->water_edicts );
else InsertLinkBefore( &ent->area, &node->solid_edicts );
if( touch_triggers && !iTouchLinkSemaphore )
@ -704,7 +703,7 @@ void SV_WaterLinks( const vec3_t origin, int *pCont, areanode_t *node )
model_t *mod;
// get water edicts
for( l = node->water_edicts.next; l != &node->water_edicts; l = next )
for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
{
next = l->next;
touch = EDICT_FROM_AREA( l );