//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include "cbase.h" #include "pvs_extender.h" #include "util_shared.h" #include "tier1/utlvector.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" static CUtlVector s_AllExtenders; CPVS_Extender::CPVS_Extender( void ) { s_AllExtenders.AddToTail( this ); } CPVS_Extender::~CPVS_Extender( void ) { s_AllExtenders.FindAndFastRemove( this ); } void CPVS_Extender::ComputeExtendedPVS( const CBaseEntity *pViewEntity, const Vector &vVisOrigin, unsigned char *outputPVS, int pvssize, int iMaxRecursions ) { int iAllExtenderCount = s_AllExtenders.Count(); if( iAllExtenderCount == 0 ) return; static CThreadFastMutex s_PVSExtenderMutex; AUTO_LOCK_FM( s_PVSExtenderMutex ); CPVS_Extender **pAllExtenders = s_AllExtenders.Base(); int iExtenderCount = 0; CPVS_Extender **pExtenders = (CPVS_Extender **)stackalloc( sizeof( CPVS_Extender * ) * iAllExtenderCount ); //filter out portals that can't possibly extend visibility up-front. So we don't have to do so in our recursions for( int i = 0; i != iAllExtenderCount; ++i ) { CPVS_Extender *pExtender = pAllExtenders[i]; Assert( pExtender ); if ( pExtender->IsExtenderValid() ) { if ( pExtender->GetExtenderNetworkProp()->AreaNum() < 0 ) { Assert( false ); continue; } pExtenders[iExtenderCount] = pExtender; ++iExtenderCount; } } if( iExtenderCount == 0 ) return; int iAreasNetworked[MAX_MAP_AREAS]; iAreasNetworked[0] = pViewEntity->NetworkProp()->AreaNum(); //safe assumption? for( int i = 1; i != MAX_MAP_AREAS; ++i ) { iAreasNetworked[i] = -1; } //unsigned char *viewEntPVS = (unsigned char *)stackalloc( sizeof( unsigned char ) * pvssize ); //memcpy( viewEntPVS, outputPVS, sizeof( unsigned char ) * pvssize ); unsigned char viewEntPVS[MAX_MAP_LEAFS/8]; engine->GetPVSForCluster( engine->GetClusterForOrigin( vVisOrigin ), sizeof( viewEntPVS ), viewEntPVS ); //do we OR that into the output PVS? //grab the local pvs of every extender up front to avoid repeating it in recursions //unsigned char *pExtenderPVSs = (unsigned char *)stackalloc( sizeof( unsigned char ) * (MAX_MAP_LEAFS/8) * iPortalCount ); ExtenderInstanceData_t *pExtenderData = (ExtenderInstanceData_t *)stackalloc( sizeof( ExtenderInstanceData_t ) * iExtenderCount ); for( int i = 0; i != iExtenderCount; ++i ) { pExtenders[i]->m_pExtenderData = &pExtenderData[i]; engine->GetPVSForCluster( engine->GetClusterForOrigin( pExtenders[i]->GetExtensionPVSOrigin() ), sizeof( unsigned char ) * (MAX_MAP_LEAFS/8), pExtenderData[i].iPVSBits ); pExtenders[i]->m_pExtenderData->bAddedToPVSAlready = false; } VisExtensionChain_t chainRoot; chainRoot.m_nArea = iAreasNetworked[0]; chainRoot.pParentChain = NULL; const edict_t *viewEdict = pViewEntity->edict(); for( int i = 0; i != iExtenderCount; ++i ) { CPVS_Extender *pExtender = pExtenders[i]; if ( pExtender->GetExtenderEdict() == viewEdict ) continue; if ( pExtender->GetExtenderNetworkProp()->IsInPVS( viewEdict, viewEntPVS, pvssize ) ) //test against pViewEntity PVS, not aggregate PVS { chainRoot.pExtender = pExtender; pExtender->ComputeSubVisibility( pExtenders, iExtenderCount, outputPVS, pvssize, vVisOrigin, NULL, 0, &chainRoot, iAreasNetworked, iMaxRecursions ); } } for( int i = 0; i != iExtenderCount; ++i ) { pExtenders[i]->m_pExtenderData = NULL; } } //does the grunt work of checking if the data has already been added, and if not, adding it /*void CPVS_Extender::AddToPVS( unsigned char *outputPVS, int pvssize, int iAreasNetworked[MAX_MAP_AREAS] ) { if( !m_pExtenderData->bAddedToPVSAlready ) { bool bFound = false; for( int i = 0; i != MAX_MAP_AREAS; ++i ) { if( iAreasNetworked[i] == iLinkedArea ) { bFound = true; break; } if( iAreasNetworked[i] == -1 ) { bFound = true; //we found it by adding it iAreasNetworked[i] = iLinkedArea; int iOutputPVSIntSize = pvssize / sizeof( unsigned int ); for( int j = 0; j != iOutputPVSIntSize; ++j ) { ((unsigned int *)outputPVS)[j] |= ((unsigned int *)pLinkedPVS)[j]; } for( int j = iOutputPVSIntSize * sizeof( unsigned int ); j != pvssize; ++j ) { outputPVS[j] |= pLinkedPVS[j]; } break; } } if( !bFound ) return; AddPortalCornersToEnginePVS( pLinkedPortal ); m_pExtenderData->bAddedToPVSAlready = true; } }*/