/* ================= R_CullGrid Returns true if the grid is completely culled away. Also sets the clipped hint bit in tess ================= */ static qboolean R_CullGrid( srfGridMesh_t *cv ) { int boxCull; int sphereCull; if ( r_nocurves->integer ) { return qtrue; } if ( tr.currentEntityNum != ENTITYNUM_WORLD ) { sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius ); } else { sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius ); } boxCull = CULL_OUT; // check for trivial reject if ( sphereCull == CULL_OUT ) { tr.pc.c_sphere_cull_patch_out++; return qtrue; } // check bounding box if necessary else if ( sphereCull == CULL_CLIP ) { tr.pc.c_sphere_cull_patch_clip++; boxCull = R_CullLocalBox( cv->meshBounds ); if ( boxCull == CULL_OUT ) { tr.pc.c_box_cull_patch_out++; return qtrue; } else if ( boxCull == CULL_IN ) { tr.pc.c_box_cull_patch_in++; } else { tr.pc.c_box_cull_patch_clip++; } } else { tr.pc.c_sphere_cull_patch_in++; } return qfalse; }
/* ============= R_CullModel ============= */ static int R_CullModel(md3Header_t * header, trRefEntity_t * ent) { vec3_t bounds[2]; md3Frame_t *oldFrame, *newFrame; int i; // compute frame pointers newFrame = (md3Frame_t *) ((byte *) header + header->ofsFrames) + ent->e.frame; oldFrame = (md3Frame_t *) ((byte *) header + header->ofsFrames) + ent->e.oldframe; // cull bounding sphere ONLY if this is not an upscaled entity if(!ent->e.nonNormalizedAxes) { if(ent->e.frame == ent->e.oldframe) { switch (R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius)) { case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; case CULL_IN: tr.pc.c_sphere_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_sphere_cull_md3_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius); if(newFrame == oldFrame) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius(oldFrame->localOrigin, oldFrame->radius); } if(sphereCull == sphereCullB) { if(sphereCull == CULL_OUT) { tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; } else if(sphereCull == CULL_IN) { tr.pc.c_sphere_cull_md3_in++; return CULL_IN; } else { tr.pc.c_sphere_cull_md3_clip++; } } } } // calculate a bounding box in the current coordinate system for(i = 0; i < 3; i++) { bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } switch (R_CullLocalBox(bounds)) { case CULL_IN: tr.pc.c_box_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_box_cull_md3_clip++; return CULL_CLIP; case CULL_OUT: default: tr.pc.c_box_cull_md3_out++; return CULL_OUT; } }
/* ============= R_CullModel ============= */ static int R_CullModel( mdcHeader_t *header, trRefEntity_t *ent ) { vec3_t bounds[2]; md3Frame_t *oldFrame, *newFrame; int i; qboolean cullSphere; //----(SA) added float radScale; cullSphere = qtrue; // compute frame pointers newFrame = ( md3Frame_t * )( ( byte * ) header + header->ofsFrames ) + ent->e.frame; oldFrame = ( md3Frame_t * )( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe; radScale = 1.0f; if ( ent->e.nonNormalizedAxes ) { cullSphere = qfalse; // by defalut, cull bounding sphere ONLY if this is not an upscaled entity // but allow the radius to be scaled if specified // if(ent->e.reFlags & REFLAG_SCALEDSPHERECULL) { // cullSphere = qtrue; // radScale = ent->e.radius; // } } if ( cullSphere ) { if ( ent->e.frame == ent->e.oldframe ) { switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius * radScale ) ) { case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; case CULL_IN: tr.pc.c_sphere_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_sphere_cull_md3_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius * radScale ); if ( newFrame == oldFrame ) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius * radScale ); } if ( sphereCull == sphereCullB ) { if ( sphereCull == CULL_OUT ) { tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; } else if ( sphereCull == CULL_IN ) { tr.pc.c_sphere_cull_md3_in++; return CULL_IN; } else { tr.pc.c_sphere_cull_md3_clip++; } } } } // calculate a bounding box in the current coordinate system for ( i = 0 ; i < 3 ; i++ ) { bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; bounds[0][i] *= radScale; //----(SA) added bounds[1][i] *= radScale; //----(SA) added } switch ( R_CullLocalBox( bounds ) ) { case CULL_IN: tr.pc.c_box_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_box_cull_md3_clip++; return CULL_CLIP; case CULL_OUT: default: tr.pc.c_box_cull_md3_out++; return CULL_OUT; } }
static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { vector3 bounds[2]; mdrFrame_t *oldFrame, *newFrame; int i, frameSize; frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); // compute frame pointers newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); // cull bounding sphere ONLY if this is not an upscaled entity if ( !ent->e.nonNormalizedAxes ) { if ( ent->e.frame == ent->e.oldframe ) { switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) { // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend // we do. After all, the purpose of md4s are not that different, are they? case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; case CULL_IN: tr.pc.c_sphere_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_sphere_cull_md3_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); if ( newFrame == oldFrame ) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); } if ( sphereCull == sphereCullB ) { if ( sphereCull == CULL_OUT ) { tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; } else if ( sphereCull == CULL_IN ) { tr.pc.c_sphere_cull_md3_in++; return CULL_IN; } else { tr.pc.c_sphere_cull_md3_clip++; } } } } // calculate a bounding box in the current coordinate system for (i = 0 ; i < 3 ; i++) { bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } switch ( R_CullLocalBox( bounds ) ) { case CULL_IN: tr.pc.c_box_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_box_cull_md3_clip++; return CULL_CLIP; case CULL_OUT: default: tr.pc.c_box_cull_md3_out++; return CULL_OUT; } }
/* ============= R_ACullModel ============= */ static int R_ACullModel( md4Header_t *header, trRefEntity_t *ent ) { vec3_t bounds[2]; md4Frame_t *oldFrame, *newFrame; int i; int frameSize; // compute frame pointers if (header->ofsFrames<0) // Compressed { frameSize = (int)( &((md4CompFrame_t *)0)->bones[ tr.currentModel->md4->numBones ] ); newFrame = (md4Frame_t *)((byte *)header - header->ofsFrames + ent->e.frame * frameSize ); oldFrame = (md4Frame_t *)((byte *)header - header->ofsFrames + ent->e.oldframe * frameSize ); // HACK! These frames actually are md4CompFrames, but the first fields are the same, // so this will work for this routine. } else { frameSize = (int)( &((md4Frame_t *)0)->bones[ tr.currentModel->md4->numBones ] ); newFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + ent->e.frame * frameSize ); oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + ent->e.oldframe * frameSize ); } // cull bounding sphere ONLY if this is not an upscaled entity if ( !ent->e.nonNormalizedAxes ) { if ( ent->e.frame == ent->e.oldframe ) { switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) { case CULL_OUT: tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; case CULL_IN: tr.pc.c_sphere_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_sphere_cull_md3_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); if ( newFrame == oldFrame ) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); } if ( sphereCull == sphereCullB ) { if ( sphereCull == CULL_OUT ) { tr.pc.c_sphere_cull_md3_out++; return CULL_OUT; } else if ( sphereCull == CULL_IN ) { tr.pc.c_sphere_cull_md3_in++; return CULL_IN; } else { tr.pc.c_sphere_cull_md3_clip++; } } } } // calculate a bounding box in the current coordinate system for (i = 0 ; i < 3 ; i++) { bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } switch ( R_CullLocalBox( bounds ) ) { case CULL_IN: tr.pc.c_box_cull_md3_in++; return CULL_IN; case CULL_CLIP: tr.pc.c_box_cull_md3_clip++; return CULL_CLIP; case CULL_OUT: default: tr.pc.c_box_cull_md3_out++; return CULL_OUT; } }
/* ================ R_CullSurface Tries to back face cull surfaces before they are lighted or added to the sorting list. This will also allow mirrors on both sides of a model without recursion. ================ */ static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader, int *frontFace ) { srfGeneric_t *gen; int cull; float d; // force to non-front facing *frontFace = 0; // allow culling to be disabled if ( r_nocull->integer ) { return qfalse; } // ydnar: made surface culling generic, inline with q3map2 surface classification switch ( *surface ) { case SF_FACE: case SF_TRIANGLES: break; case SF_GRID: if ( r_nocurves->integer ) { return qtrue; } break; case SF_FOLIAGE: if ( !r_drawfoliage->value ) { return qtrue; } break; default: return qtrue; } // get generic surface gen = ( srfGeneric_t * ) surface; // plane cull if ( gen->plane.type != PLANE_NON_PLANAR && r_facePlaneCull->integer ) { d = DotProduct( tr.orientation.viewOrigin, gen->plane.normal ) - gen->plane.dist; if ( d > 0.0f ) { *frontFace = 1; } // don't cull exactly on the plane, because there are levels of rounding // through the BSP, ICD, and hardware that may cause pixel gaps if an // epsilon isn't allowed here if ( shader->cullType == CT_FRONT_SIDED ) { if ( d < -8.0f ) { tr.pc.c_plane_cull_out++; return qtrue; } } else if ( shader->cullType == CT_BACK_SIDED ) { if ( d > 8.0f ) { tr.pc.c_plane_cull_out++; return qtrue; } } tr.pc.c_plane_cull_in++; } { // try sphere cull if ( tr.currentEntityNum != ENTITYNUM_WORLD ) { cull = R_CullLocalPointAndRadius( gen->origin, gen->radius ); } else { cull = R_CullPointAndRadius( gen->origin, gen->radius ); } if ( cull == CULL_OUT ) { tr.pc.c_sphere_cull_out++; return qtrue; } tr.pc.c_sphere_cull_in++; } // must be visible return qfalse; }
/** * @brief R_CullMDV * @param[in] model * @param[in,out] ent */ static void R_CullMDV(mdvModel_t *model, trRefEntity_t *ent) { int i; // compute frame pointers mdvFrame_t *newFrame = model->frames + ent->e.frame; mdvFrame_t *oldFrame = model->frames + ent->e.oldframe; // calculate a bounding box in the current coordinate system for (i = 0; i < 3; i++) { ent->localBounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; ent->localBounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } // setup world bounds for intersection tests R_SetupEntityWorldBounds(ent); // cull bounding sphere ONLY if this is not an upscaled entity if (!ent->e.nonNormalizedAxes) { if (ent->e.frame == ent->e.oldframe) { switch (R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius)) { case CULL_OUT: tr.pc.c_sphere_cull_mdx_out++; ent->cull = CULL_OUT; return; case CULL_IN: tr.pc.c_sphere_cull_mdx_in++; ent->cull = CULL_IN; return; case CULL_CLIP: tr.pc.c_sphere_cull_mdx_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius); if (newFrame == oldFrame) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius(oldFrame->localOrigin, oldFrame->radius); } if (sphereCull == sphereCullB) { if (sphereCull == CULL_OUT) { tr.pc.c_sphere_cull_mdx_out++; ent->cull = CULL_OUT; return; } else if (sphereCull == CULL_IN) { tr.pc.c_sphere_cull_mdx_in++; ent->cull = CULL_IN; return; } else { tr.pc.c_sphere_cull_mdx_clip++; } } } } switch (R_CullBox(ent->worldBounds)) { case CULL_IN: tr.pc.c_box_cull_mdx_in++; ent->cull = CULL_IN; return; case CULL_CLIP: tr.pc.c_box_cull_mdx_clip++; ent->cull = CULL_CLIP; return; case CULL_OUT: default: tr.pc.c_box_cull_mdx_out++; ent->cull = CULL_OUT; return; } }