/* * R_CullBrushModel */ qboolean R_CullBrushModel( entity_t *e ) { qboolean rotated; vec3_t mins, maxs; float radius; model_t *model = e->model; mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata; if( bmodel->nummodelsurfaces == 0 ) return qtrue; radius = R_BrushModelBBox( e, mins, maxs, &rotated ); if( rotated ) { if( R_CullSphere( e->origin, radius, ri.clipFlags ) ) return qtrue; } else { if( R_CullBox( mins, maxs, ri.clipFlags ) ) return qtrue; } if( ri.params & RP_PVSCULL ) { if( rotated ) { if( R_VisCullSphere( e->origin, radius ) ) return qtrue; } else { if( R_VisCullBox( mins, maxs ) ) return qtrue; } } return qfalse; }
/* * R_AddBrushModelToDrawList */ qboolean R_AddBrushModelToDrawList( const entity_t *e ) { unsigned int i; vec3_t origin; vec3_t bmins, bmaxs; qboolean rotated; model_t *model = e->model; mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata; msurface_t *surf; mfog_t *fog; float radius, distance; unsigned int bit, fullBits; unsigned int dlightBits, shadowBits; if( bmodel->nummodelsurfaces == 0 ) { return qfalse; } radius = R_BrushModelBBox( e, bmins, bmaxs, &rotated ); if( R_CullModelEntity( e, bmins, bmaxs, radius, rotated ) ) { return qfalse; } // never render weapon models or non-occluders into shadowmaps if( rn.renderFlags & RF_SHADOWMAPVIEW ) { if( rsc.entShadowGroups[R_ENT2NUM(e)] != rn.shadowGroup->id ) { return qtrue; } } VectorAdd( e->model->mins, e->model->maxs, origin ); VectorMA( e->origin, 0.5, origin, origin ); distance = Distance( origin, rn.refdef.vieworg ); fog = R_FogForBounds( bmins, bmaxs ); R_TransformPointToModelSpace( e, rotated, rn.refdef.vieworg, modelOrg ); // check dynamic lights that matter in the instance against the model dlightBits = 0; for( i = 0, fullBits = rn.dlightBits, bit = 1; fullBits; i++, fullBits &= ~bit, bit <<= 1 ) { if( !( fullBits & bit ) ) { continue; } if( !BoundsAndSphereIntersect( bmins, bmaxs, rsc.dlights[i].origin, rsc.dlights[i].intensity ) ) { continue; } dlightBits |= bit; } // check shadowmaps that matter in the instance against the model shadowBits = 0; for( i = 0, fullBits = rn.shadowBits; fullBits; i++, fullBits &= ~bit ) { shadowGroup_t *grp = rsc.shadowGroups + i; bit = grp->bit; if( !( fullBits & bit ) ) { continue; } if( !BoundsIntersect( bmins, bmaxs, grp->visMins, grp->visMaxs ) ) { continue; } shadowBits |= bit; } for( i = 0, surf = bmodel->firstmodelsurface; i < bmodel->nummodelsurfaces; i++, surf++ ) { if( !surf->drawSurf ) { continue; } if( surf->visFrame != rf.frameCount ) { surf->visFrame = rf.frameCount; R_AddSurfaceToDrawList( e, surf, fog, 0, dlightBits, shadowBits, distance ); } } return qtrue; }
/* * R_AddLightOccluder */ bool R_AddLightOccluder( const entity_t *ent ) { int i; float maxSide; vec3_t origin; unsigned int hash_key; shadowGroup_t *group; mleaf_t *leaf; vec3_t mins, maxs, bbox[8]; bool bmodelRotated = false; if( rn.refdef.rdflags & RDF_NOWORLDMODEL ) { return false; } if( !ent->model || ent->model->type == mod_brush ) { return false; } VectorCopy( ent->lightingOrigin, origin ); if( ent->model->type == mod_brush ) { vec3_t t; VectorAdd( ent->model->mins, ent->model->maxs, t ); VectorMA( ent->origin, 0.5, t, origin ); } if( VectorCompare( origin, vec3_origin ) ) { return false; } // find lighting group containing entities with same lightingOrigin as ours hash_key = (unsigned int)( origin[0] * 7 + origin[1] * 5 + origin[2] * 3 ); hash_key &= ( SHADOWGROUPS_HASH_SIZE - 1 ); for( group = r_shadowGroups_hash[hash_key]; group; group = group->hashNext ) { if( VectorCompare( group->origin, origin ) ) { goto add; // found an existing one, add } } if( rsc.numShadowGroups == MAX_SHADOWGROUPS ) { return false; // no free groups } leaf = Mod_PointInLeaf( origin, rsh.worldModel ); // start a new group group = &rsc.shadowGroups[rsc.numShadowGroups]; memset( group, 0, sizeof( *group ) ); group->id = group - rsc.shadowGroups + 1; group->bit = ( 1 << rsc.numShadowGroups ); group->vis = Mod_ClusterPVS( leaf->cluster, rsh.worldModel ); group->useOrtho = true; group->alpha = r_shadows_alpha->value; // clear group bounds VectorCopy( origin, group->origin ); ClearBounds( group->mins, group->maxs ); ClearBounds( group->visMins, group->visMaxs ); // add to hash table group->hashNext = r_shadowGroups_hash[hash_key]; r_shadowGroups_hash[hash_key] = group; rsc.numShadowGroups++; add: // get model bounds if( ent->model->type == mod_alias ) { R_AliasModelBBox( ent, mins, maxs ); } else if( ent->model->type == mod_skeletal ) { R_SkeletalModelBBox( ent, mins, maxs ); } else if( ent->model->type == mod_brush ) { R_BrushModelBBox( ent, mins, maxs, &bmodelRotated ); } else { ClearBounds( mins, maxs ); } maxSide = 0; for( i = 0; i < 3; i++ ) { if( mins[i] >= maxs[i] ) { return false; } maxSide = max( maxSide, maxs[i] - mins[i] ); } // ignore tiny objects if( maxSide < 10 ) { return false; } rsc.entShadowGroups[R_ENT2NUM( ent )] = group->id; if( ent->flags & RF_WEAPONMODEL ) { return true; } if( ent->model->type == mod_brush ) { VectorCopy( mins, group->mins ); VectorCopy( maxs, group->maxs ); } else { // rotate local bounding box and compute the full bounding box for this group R_TransformBounds( ent->origin, ent->axis, mins, maxs, bbox ); for( i = 0; i < 8; i++ ) { AddPointToBounds( bbox[i], group->mins, group->maxs ); } } // increase projection distance if needed VectorSubtract( group->mins, origin, mins ); VectorSubtract( group->maxs, origin, maxs ); group->radius = RadiusFromBounds( mins, maxs ); group->projDist = max( group->projDist, group->radius + min( r_shadows_projection_distance->value, 64.0f ) ); return true; }