/* gl_cull.c - render culling routines Copyright (C) 2010 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 "gl_local.h" #include "entity_types.h" /* ============================================================= FRUSTUM AND PVS CULLING ============================================================= */ /* ================= R_CullBox Returns true if the box is completely outside the frustum ================= */ qboolean R_CullBox( const vec3_t mins, const vec3_t maxs ) { return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 ); } /* ================= R_CullSphere Returns true if the sphere is completely outside the frustum ================= */ qboolean R_CullSphere( const vec3_t centre, const float radius ) { return GL_FrustumCullSphere( &RI.frustum, centre, radius, 0 ); } /* ============= R_CullModel ============= */ int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax ) { if( e == gEngfuncs.GetViewModel() ) { if( ENGINE_GET_PARM( PARM_DEV_OVERVIEW )) return 1; if( RP_NORMALPASS() && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer()) return 0; return 1; } // local client can't view himself if camera or thirdperson is not active if( RP_LOCALCLIENT( e ) && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer()) return 1; if( R_CullBox( absmin, absmax )) return 1; return 0; } /* ================= R_CullSurface cull invisible surfaces ================= */ int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags ) { cl_entity_t *e = RI.currententity; if( !surf || !surf->texinfo || !surf->texinfo->texture ) return CULL_OTHER; if( r_nocull->value ) return CULL_VISIBLE; // world surfaces can be culled by vis frame too if( RI.currententity == gEngfuncs.GetEntityByIndex( 0 ) && surf->visframe != tr.framecount ) return CULL_VISFRAME; // only static ents can be culled by frustum if( !R_StaticEntity( e )) frustum = NULL; if( !VectorIsNull( surf->plane->normal )) { float dist; // can use normal.z for world (optimisation) if( RI.drawOrtho ) { vec3_t orthonormal; if( e == gEngfuncs.GetEntityByIndex( 0 ) ) orthonormal[2] = surf->plane->normal[2]; else Matrix4x4_VectorRotate( RI.objectMatrix, surf->plane->normal, orthonormal ); dist = orthonormal[2]; } else dist = PlaneDiff( tr.modelorg, surf->plane ); if( glState.faceCull == GL_FRONT ) { if( FBitSet( surf->flags, SURF_PLANEBACK )) { if( dist >= -BACKFACE_EPSILON ) return CULL_BACKSIDE; // wrong side } else { if( dist <= BACKFACE_EPSILON ) return CULL_BACKSIDE; // wrong side } } else if( glState.faceCull == GL_BACK ) { if( FBitSet( surf->flags, SURF_PLANEBACK )) { if( dist <= BACKFACE_EPSILON ) return CULL_BACKSIDE; // wrong side } else { if( dist >= -BACKFACE_EPSILON ) return CULL_BACKSIDE; // wrong side } } } if( frustum && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags )) return CULL_FRUSTUM; return CULL_VISIBLE; }