void R_CullDecalProjectors( void ) { int i, numDecalProjectors, decalBits; decalProjector_t *dp; /* limit */ if ( tr.refdef.numDecalProjectors > MAX_DECAL_PROJECTORS ) { tr.refdef.numDecalProjectors = MAX_DECAL_PROJECTORS; } /* walk decal projector list */ numDecalProjectors = 0; decalBits = 0; for ( i = 0, dp = tr.refdef.decalProjectors; i < tr.refdef.numDecalProjectors; i++, dp++ ) { if ( R_CullPointAndRadius( dp->center, dp->radius ) == CULL_OUT ) { dp->shader = NULL; } else { numDecalProjectors = i + 1; decalBits |= ( 1 << i ); } } /* reset count */ tr.refdef.numDecalProjectors = numDecalProjectors; tr.pc.c_decalProjectors = numDecalProjectors; /* set bits */ tr.refdef.decalBits = decalBits; }
void R_CullDlights( void ) { int i, numDlights, dlightBits; dlight_t *dl; /* limit */ if ( tr.refdef.num_dlights > MAX_DLIGHTS ) { tr.refdef.num_dlights = MAX_DLIGHTS; } /* walk dlight list */ numDlights = 0; dlightBits = 0; for ( i = 0, dl = tr.refdef.dlights; i < tr.refdef.num_dlights; i++, dl++ ) { if ( ( dl->flags & REF_DIRECTED_DLIGHT ) || R_CullPointAndRadius( dl->origin, dl->radius ) != CULL_OUT ) { numDlights = i + 1; dlightBits |= ( 1 << i ); } } /* reset count */ tr.refdef.num_dlights = numDlights; /* set bits */ tr.refdef.dlightBits = dlightBits; }
// frustum culls decal projector list void R_CullDecalProjectors() { // limit if ( tr.refdef.numDecalProjectors > MAX_DECAL_PROJECTORS ) { tr.refdef.numDecalProjectors = MAX_DECAL_PROJECTORS; } // walk decal projector list int numDecalProjectors = 0; int decalBits = 0; decalProjector_t* dp = tr.refdef.decalProjectors; for ( int i = 0; i < tr.refdef.numDecalProjectors; i++, dp++ ) { if ( R_CullPointAndRadius( dp->center, dp->radius ) == CULL_OUT ) { dp->shader = NULL; } else { numDecalProjectors = i + 1; decalBits |= ( 1 << i ); } } // reset count tr.refdef.numDecalProjectors = numDecalProjectors; tr.pc.c_decalProjectors = numDecalProjectors; // set bits tr.refdef.decalBits = decalBits; }
/* ** R_CullLocalPointAndRadius */ int R_CullLocalPointAndRadius( vec3_t pt, float radius ) { vec3_t transformed; R_LocalPointToWorld( pt, transformed ); return R_CullPointAndRadius( transformed, radius ); }
int R_CullLocalPointAndRadius( vector3 *pt, float radius ) { vector3 transformed; R_LocalPointToWorld( pt, &transformed ); return R_CullPointAndRadius( &transformed, radius ); }
/* ================= 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_CullMD5 ============= */ static void R_CullMD5( trRefEntity_t *ent ) { int i; float boundsRadius; if ( ent->e.skeleton.type == SK_INVALID ) { // no properly set skeleton so use the bounding box by the model instead by the animations md5Model_t *model = tr.currentModel->md5;; VectorCopy( model->bounds[ 0 ], ent->localBounds[ 0 ] ); VectorCopy( model->bounds[ 1 ], ent->localBounds[ 1 ] ); } else { // copy a bounding box in the current coordinate system provided by skeleton for ( i = 0; i < 3; i++ ) { ent->localBounds[ 0 ][ i ] = ent->e.skeleton.bounds[ 0 ][ i ]; ent->localBounds[ 1 ][ i ] = ent->e.skeleton.bounds[ 1 ][ i ]; } } boundsRadius = RadiusFromBounds( ent->localBounds[ 0 ], ent->localBounds[ 1 ] ); switch ( R_CullPointAndRadius( ent->e.origin, boundsRadius ) ) { case CULL_IN: tr.pc.c_box_cull_md5_in++; ent->cull = CULL_IN; return; case CULL_CLIP: tr.pc.c_box_cull_md5_clip++; ent->cull = CULL_CLIP; return; case CULL_OUT: default: tr.pc.c_box_cull_md5_out++; ent->cull = CULL_OUT; return; } }
/** * @brief Frustum culls decal projector list */ void R_CullDecalProjectors(void) { int i, numDecalProjectors, decalBits; decalProjector_t *dp, temp; // walk decal projector list numDecalProjectors = 0; decalBits = 0; for (i = 0, dp = tr.refdef.decalProjectors; i < tr.refdef.numDecalProjectors; i++, dp++) { if (R_CullPointAndRadius(dp->center, dp->radius) == CULL_OUT) { continue; } // put all active projectors at the beginning if (tr.refdef.numDecalProjectors > MAX_USED_DECAL_PROJECTORS && dp != &tr.refdef.decalProjectors[numDecalProjectors]) { // swap them temp = tr.refdef.decalProjectors[numDecalProjectors]; tr.refdef.decalProjectors[numDecalProjectors] = *dp; *dp = temp; } decalBits |= (1 << numDecalProjectors); numDecalProjectors++; // bitmask limit if (numDecalProjectors == MAX_USED_DECAL_PROJECTORS) { break; } } // reset count tr.refdef.numDecalProjectors = numDecalProjectors; tr.pc.c_decalProjectors = numDecalProjectors; // set bits tr.refdef.decalBits = decalBits; }
/* R_CullDecalProjectors() frustum culls decal projector list */ void R_CullDecalProjectors(void) { int i, numDecalProjectors, decalBits; decalProjector_t *dp, temp; /* walk decal projector list */ numDecalProjectors = 0; decalBits = 0; for (i = 0, dp = tr.refdef.decalProjectors; i < tr.refdef.numDecalProjectors; i++, dp++) { if (R_CullPointAndRadius(dp->center, dp->radius) == CULL_OUT) { continue; } /* put all active projectors at the beginning */ if (tr.refdef.numDecalProjectors > 32 && dp != &tr.refdef.decalProjectors[numDecalProjectors]) { /* swap them */ temp = tr.refdef.decalProjectors[numDecalProjectors]; tr.refdef.decalProjectors[numDecalProjectors] = *dp; *dp = temp; } decalBits |= (1 << numDecalProjectors); numDecalProjectors++; /* bitmask limit */ if (numDecalProjectors == 32) { break; } } /* reset count */ tr.refdef.numDecalProjectors = numDecalProjectors; tr.pc.c_decalProjectors = numDecalProjectors; /* set bits */ tr.refdef.decalBits = decalBits; }
/* ** R_CullLocalPointAndRadius */ int R_CullLocalPointAndRadius( vec3_t pt, float radius ) { vec3_t transformed; /* Ghoul2 Insert Start */ vec3_t zero = {0.0f,0.0f,0.0f}; // if we didn't get a local origin, make it all 0's if (!pt) { pt = zero; } /* Ghoul2 Insert End */ R_LocalPointToWorld( pt, transformed ); return R_CullPointAndRadius( transformed, radius ); }
void RE_ProjectDecal( qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime ) { int i; float radius, iDist; vec3_t xyz; vec4_t omniProjection; decalVert_t dv[ 4 ]; decalProjector_t *dp, temp; /* first frame rendered does not have a valid decals list */ if ( tr.refdef.decalProjectors == NULL ) { return; } /* dummy check */ if ( numPoints != 1 && numPoints != 3 && numPoints != 4 ) { ri.Printf( PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints ); return; } /* early outs */ if ( lifeTime == 0 ) { return; } if ( projection[ 3 ] <= 0.0f ) { return; } /* set times properly */ if ( lifeTime < 0 || fadeTime < 0 ) { lifeTime = 0; fadeTime = 0; } /* basic setup */ temp.shader = R_GetShaderByHandle( hShader ); /* debug code */ temp.numPlanes = temp.shader->entityMergable; temp.color[ 0 ] = color[ 0 ] * 255; temp.color[ 1 ] = color[ 1 ] * 255; temp.color[ 2 ] = color[ 2 ] * 255; temp.color[ 3 ] = color[ 3 ] * 255; temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; temp.fadeEndTime = temp.fadeStartTime + fadeTime; /* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */ dv[ 0 ].st[ 0 ] = 0.0f; dv[ 0 ].st[ 1 ] = 0.0f; dv[ 1 ].st[ 0 ] = 0.0f; dv[ 1 ].st[ 1 ] = 1.0f; dv[ 2 ].st[ 0 ] = 1.0f; dv[ 2 ].st[ 1 ] = 1.0f; dv[ 3 ].st[ 0 ] = 1.0f; dv[ 3 ].st[ 1 ] = 0.0f; /* omnidirectional? */ if ( numPoints == 1 ) { /* set up omnidirectional */ numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[ 3 ]; Vector4Set( omniProjection, 0.0f, 0.0f, -1.0f, radius * 2.0f ); projection = omniProjection; iDist = 1.0f / ( radius * 2.0f ); /* set corner */ VectorSet( xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); /* make x axis texture matrix (yz) */ VectorSet( temp.texMat[ 0 ][ 0 ], 0.0f, iDist, 0.0f ); temp.texMat[ 0 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 0 ], xyz ); VectorSet( temp.texMat[ 0 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 0 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 1 ], xyz ); /* make y axis texture matrix (xz) */ VectorSet( temp.texMat[ 1 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 1 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 0 ], xyz ); VectorSet( temp.texMat[ 1 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 1 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 1 ], xyz ); /* make z axis texture matrix (xy) */ VectorSet( temp.texMat[ 2 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 2 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 0 ], xyz ); VectorSet( temp.texMat[ 2 ][ 1 ], 0.0f, iDist, 0.0f ); temp.texMat[ 2 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 1 ], xyz ); /* setup decal points */ VectorSet( dv[ 0 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 1 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 2 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 3 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); } else { /* set up unidirectional */ temp.omnidirectional = qfalse; /* set up decal points */ VectorCopy( points[ 0 ], dv[ 0 ].xyz ); VectorCopy( points[ 1 ], dv[ 1 ].xyz ); VectorCopy( points[ 2 ], dv[ 2 ].xyz ); VectorCopy( points[ 3 ], dv[ 3 ].xyz ); /* make texture matrix */ if ( !MakeTextureMatrix( temp.texMat[ 0 ], projection, &dv[ 0 ], &dv[ 1 ], &dv[ 2 ] ) ) { return; } } /* bound the projector */ ClearBounds( temp.mins, temp.maxs ); for ( i = 0; i < numPoints; i++ ) { AddPointToBounds( dv[ i ].xyz, temp.mins, temp.maxs ); VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); AddPointToBounds( xyz, temp.mins, temp.maxs ); } /* make bounding sphere */ VectorAdd( temp.mins, temp.maxs, temp.center ); VectorScale( temp.center, 0.5f, temp.center ); VectorSubtract( temp.maxs, temp.center, xyz ); temp.radius = VectorLength( xyz ); temp.radius2 = temp.radius * temp.radius; /* frustum cull the projector (fixme: this uses a stale frustum!) */ if ( R_CullPointAndRadius( temp.center, temp.radius ) == CULL_OUT ) { return; } /* make the front plane */ if ( !PlaneFromPoints( temp.planes[ 0 ], dv[ 0 ].xyz, dv[ 1 ].xyz, dv[ 2 ].xyz ) ) { return; } /* make the back plane */ VectorSubtract( vec3_origin, temp.planes[ 0 ], temp.planes[ 1 ] ); VectorMA( dv[ 0 ].xyz, projection[ 3 ], projection, xyz ); temp.planes[ 1 ][ 3 ] = DotProduct( xyz, temp.planes[ 1 ] ); /* make the side planes */ for ( i = 0; i < numPoints; i++ ) { VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); if ( !PlaneFromPoints( temp.planes[ i + 2 ], dv[( i + 1 ) % numPoints ].xyz, dv[ i ].xyz, xyz ) ) { return; } } /* create a new projector */ dp = &tr.refdef.decalProjectors[ r_numDecalProjectors & DECAL_PROJECTOR_MASK ]; Com_Memcpy( dp, &temp, sizeof( *dp ) ); /* we have a winner */ r_numDecalProjectors++; }
/* ================ 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; }