/* * R_MarkLeaves * * Mark the leaves and nodes that are in the PVS for the current cluster */ void R_MarkLeaves( void ) { qbyte *pvs; unsigned int i; int rdflags; mleaf_t *leaf, **pleaf; mnode_t *node; qbyte *areabits; int cluster; qbyte fatpvs[MAX_MAP_LEAFS/8]; rdflags = rn.refdef.rdflags; if( rdflags & RDF_NOWORLDMODEL ) return; if( rf.oldviewcluster == rf.viewcluster && ( rdflags & RDF_OLDAREABITS ) && !(rn.renderFlags & RF_NOVIS) && rf.viewcluster != -1 && rf.oldviewcluster != -1 ) return; if( rn.renderFlags & RF_SHADOWMAPVIEW ) return; if( !rsh.worldModel ) return; // development aid to let you run around and see exactly where // the pvs ends if( r_lockpvs->integer ) return; rf.pvsframecount++; rf.oldviewcluster = rf.viewcluster; if( rn.renderFlags & RF_NOVIS || rf.viewcluster == -1 || !rsh.worldBrushModel->pvs ) { // mark everything for( pleaf = rsh.worldBrushModel->visleafs, leaf = *pleaf; leaf; leaf = *pleaf++ ) leaf->pvsframe = rf.pvsframecount; for( i = 0, node = rsh.worldBrushModel->nodes; i < rsh.worldBrushModel->numnodes; i++, node++ ) node->pvsframe = rf.pvsframecount; return; } pvs = Mod_ClusterPVS( rf.viewcluster, rsh.worldModel ); if( rf.viewarea > -1 && rn.refdef.areabits ) #ifdef AREAPORTALS_MATRIX areabits = rn.refdef.areabits + rf.viewarea * ((rsh.worldBrushModel->numareas+7)/8); #else areabits = rn.refdef.areabits; #endif else
/* * Mod_CreateSubmodelBufferObjects */ static int Mod_CreateSubmodelBufferObjects( model_t *mod, unsigned int modnum, size_t *vbo_total_size ) { unsigned int i, j, k; uint8_t *visdata = NULL; uint8_t *areadata = NULL; unsigned int rowbytes, rowlongs; int areabytes; uint8_t *arearow; int *longrow, *longrow2; mmodel_t *bm; mbrushmodel_t *loadbmodel; msurface_t *surf, *surf2, **mark; msurface_t **surfmap; msurface_t **surfaces; unsigned numSurfaces; unsigned numUnmappedSurfaces; unsigned startDrawSurface; drawSurfaceBSP_t *drawSurf; int num_vbos; vattribmask_t floatVattribs; mesh_vbo_t *tempVBOs; unsigned numTempVBOs, maxTempVBOs; unsigned numUnmergedVBOs; assert( mod ); loadbmodel = (( mbrushmodel_t * )mod->extradata); assert( loadbmodel ); assert( modnum >= 0 && modnum < loadbmodel->numsubmodels ); bm = loadbmodel->submodels + modnum; // ignore empty models if( !bm->numfaces ) return 0; surfmap = ( msurface_t ** )Mod_Malloc( mod, bm->numfaces * sizeof( *surfmap ) ); surfaces = ( msurface_t ** )Mod_Malloc( mod, bm->numfaces * sizeof( *surfaces ) ); numSurfaces = 0; numTempVBOs = 0; maxTempVBOs = 1024; tempVBOs = ( mesh_vbo_t * )Mod_Malloc( mod, maxTempVBOs * sizeof( *tempVBOs ) ); startDrawSurface = loadbmodel->numDrawSurfaces; if( !modnum && loadbmodel->pvs ) { mleaf_t *leaf, **pleaf; rowbytes = loadbmodel->pvs->rowsize; rowlongs = (rowbytes + 3) / 4; areabytes = (loadbmodel->numareas + 7) / 8; if( !rowbytes ) return 0; // build visibility data for each face, based on what leafs // this face belongs to (visible from) visdata = ( uint8_t * )Mod_Malloc( mod, rowlongs * 4 * loadbmodel->numsurfaces ); areadata = ( uint8_t * )Mod_Malloc( mod, areabytes * loadbmodel->numsurfaces ); for( pleaf = loadbmodel->visleafs, leaf = *pleaf; leaf; leaf = *pleaf++ ) { mark = leaf->firstVisSurface; do { int surfnum; surf = *mark++; surfnum = surf - loadbmodel->surfaces; if( surfmap[surfnum] ) { continue; } surfmap[surfnum] = surf; surfaces[numSurfaces] = surf; longrow = ( int * )( visdata + numSurfaces * rowbytes ); longrow2 = ( int * )( Mod_ClusterPVS( leaf->cluster, mod ) ); // merge parent leaf cluster visibility into face visibility set // we could probably check for duplicates here because face can be // shared among multiple leafs for( j = 0; j < rowlongs; j++ ) longrow[j] |= longrow2[j]; if( leaf->area >= 0 ) { arearow = areadata + numSurfaces * areabytes; arearow[leaf->area>>3] |= (1<<(leaf->area&7)); } numSurfaces++; } while( *mark ); }
/* * Mod_CreateSubmodelBufferObjects */ static int Mod_CreateSubmodelBufferObjects( model_t *mod, unsigned int modnum, size_t *vbo_total_size ) { unsigned int i, j, k; qbyte *visdata = NULL; qbyte *areadata = NULL; unsigned int rowbytes, rowlongs; int areabytes; qbyte *arearow; int *longrow, *longrow2; mmodel_t *bm; mbrushmodel_t *loadbmodel; msurface_t *surf, *surf2, **mark; msurface_t **surfmap; drawSurfaceBSP_t *drawSurf; int num_vbos; assert( mod ); loadbmodel = (( mbrushmodel_t * )mod->extradata); assert( loadbmodel ); assert( modnum >= 0 && modnum < loadbmodel->numsubmodels ); bm = loadbmodel->submodels + modnum; // ignore empty models if( !bm->numfaces ) return 0; // PVS only exists for world submodel if( !modnum && loadbmodel->pvs ) { mleaf_t *leaf, **pleaf; rowbytes = loadbmodel->pvs->rowsize; rowlongs = (rowbytes + 3) / 4; areabytes = (loadbmodel->numareas + 7) / 8; if( !rowbytes ) return 0; // build visibility data for each face, based on what leafs // this face belongs to (visible from) visdata = Mod_Malloc( mod, rowlongs * 4 * loadbmodel->numsurfaces ); areadata = Mod_Malloc( mod, areabytes * loadbmodel->numsurfaces ); for( pleaf = loadbmodel->visleafs, leaf = *pleaf; leaf; leaf = *pleaf++ ) { mark = leaf->firstVisSurface; do { int surfnum; surf = *mark; surfnum = surf - loadbmodel->surfaces; longrow = ( int * )( visdata + surfnum * rowbytes ); longrow2 = ( int * )( Mod_ClusterPVS( leaf->cluster, mod ) ); // merge parent leaf cluster visibility into face visibility set // we could probably check for duplicates here because face can be // shared among multiple leafs for( j = 0; j < rowlongs; j++ ) longrow[j] |= longrow2[j]; if( leaf->area >= 0 ) { arearow = areadata + surfnum * areabytes; arearow[leaf->area>>3] |= (1<<(leaf->area&7)); } } while( *++mark ); } }
/* * 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; }