VisEntryIndex CPlayerVisTable::GetEntityIndexFromID(EntityId entityId) { CRY_TODO(30,09,2009, "Make faster"); CryPrefetch(((char*)m_visTableEntries) + 128); for(VisEntryIndex i = 0; i < m_numUsedVisTableEntries; i++) { SVisTableEntry& visInfo = m_visTableEntries[i]; if(m_visTableEntries[i].entityId == entityId) { return i; } } return -1; }
//------------------------------------------------------------------------ void CTracerManager::Update(float frameTime) { CryPrefetch(m_tracerPool); const CCamera& viewCamera = gEnv->pSystem->GetViewCamera(); const Vec3 cameraPosition = viewCamera.GetPosition(); const float viewCameraFovScale = viewCamera.GetFov() / DEG2RAD(g_pGame->GetFOV()); const int kNumActiveTracers = m_numActiveTracers; for(int i = 0; i < kNumActiveTracers;) { int nextTracerIndex = i + 1; CTracer& tracer = m_tracerPool[i]; CryPrefetch(&m_tracerPool[nextTracerIndex]); //Update const bool stillMoving = tracer.Update(frameTime, cameraPosition, viewCameraFovScale); //Is it worth putting this in another loop for instruction cache coherency? Profile when PS3 is up and running - Rich S if(stillMoving || (tracer.m_fadeOutTime > 0.f)) { tracer.m_tracerFlags |= kTracerFlag_active; if (!stillMoving) { tracer.m_fadeOutTime -= frameTime; if (tracer.m_effectSlot > -1) { if (IEntity *pEntity = gEnv->pEntitySystem->GetEntity(tracer.m_entityId)) { IParticleEmitter * emitter = pEntity->GetParticleEmitter(tracer.m_effectSlot); if (emitter) { emitter->Activate(false); } if (tracer.m_tracerFlags & kTracerFlag_useGeometry) { pEntity->SetSlotFlags(tracer.m_geometrySlot, pEntity->GetSlotFlags(tracer.m_geometrySlot) &~ (ENTITY_SLOT_RENDER|ENTITY_SLOT_RENDER_NEAREST)); } tracer.m_effectSlot = -1; } } if(tracer.m_tracerFlags & kTracerFlag_useGeometry) { // Fade out geometry if((tracer.m_fadeOutTime < tracer.m_startFadeOutTime) && (tracer.m_startFadeOutTime > 0.0f)) { if (IEntity *pEntity = gEnv->pEntitySystem->GetEntity(tracer.m_entityId)) { IEntityRenderProxy *pRenderProxy = (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER); pRenderProxy->SetOpacity(max((tracer.m_fadeOutTime / tracer.m_startFadeOutTime) * tracer.m_geometryOpacity, 0.0f)); } } } } } else { tracer.m_tracerFlags &= ~kTracerFlag_active; tracer.m_boundToBulletId = 0; } i = nextTracerIndex; } //This is where we clear out the inactive tracers, so the counter isn't const int numActiveTracers = kNumActiveTracers; CWeaponSystem* pWeaponSystem = g_pGame->GetWeaponSystem(); for(int i = kNumActiveTracers - 1; i >= 0;) { int nextIndex = i - 1; CTracer& tracer = m_tracerPool[i]; CryPrefetch(&m_tracerPool[nextIndex]); if(!(tracer.m_tracerFlags & kTracerFlag_active)) { if (IEntity *pEntity=gEnv->pEntitySystem->GetEntity(tracer.m_entityId)) { pEntity->Hide(true); pEntity->FreeSlot(TRACER_GEOM_SLOT); pEntity->FreeSlot(TRACER_FX_SLOT); } //Switch the inactive tracer so it's at the end of the array; const int lastTracer = numActiveTracers - 1; static CTracer temp; temp = tracer; numActiveTracers = lastTracer; tracer = m_tracerPool[lastTracer]; m_tracerPool[lastTracer] = temp; //Re-bind index to the corresponding bullet if (tracer.m_boundToBulletId) { CProjectile* pProjectile = pWeaponSystem->GetProjectile(tracer.m_boundToBulletId); if (pProjectile && pProjectile->IsAlive()) { if(lastTracer == pProjectile->GetTracerIdx()) { pProjectile->BindToTracer(i); } else if(lastTracer == pProjectile->GetThreatTrailTracerIdx()) { pProjectile->BindToThreatTrailTracer(i); } } } } i = nextIndex; } m_numActiveTracers = numActiveTracers; }
int CPlayerVisTable::AddVisTableEntriesToPriorityList() { int numAdded = 0; int worstPriority = std::numeric_limits<int>::min(); int worstPriorityIndex = 0; const int kNumUsedVisTableEntries = m_numUsedVisTableEntries; for(int i = 0; i < kNumUsedVisTableEntries; i++) { CryPrefetch(&m_visTableEntries[i+4]); SVisTableEntry& visInfo = m_visTableEntries[i]; const int lastRequestedLatency = visInfo.lastRequestedLatency; const int framesSinceLastCheck = visInfo.framesSinceLastCheck; int newEntryPriority = lastRequestedLatency - framesSinceLastCheck; if ((visInfo.flags & eVF_Requested) && !(visInfo.flags & eVF_Pending)) { if(numAdded < kMaxVisTableLinetestsPerFrame) { SVisTablePriority& visPriority = m_visTablePriorities[numAdded]; visPriority.visInfo = &visInfo; visPriority.priority = newEntryPriority; visPriority.visIndex = i; if(newEntryPriority > worstPriority) { worstPriority = newEntryPriority; worstPriorityIndex = numAdded; } numAdded++; } else if(newEntryPriority < worstPriority) { SVisTablePriority& worstVisPriority = m_visTablePriorities[worstPriorityIndex]; worstPriority = newEntryPriority; worstVisPriority.priority = newEntryPriority; worstVisPriority.visInfo = &visInfo; worstVisPriority.visIndex = i; for(int j = 0; j < numAdded; j++) { SVisTablePriority& visP = m_visTablePriorities[j]; if(worstPriority <= visP.priority ) { worstPriority = visP.priority; worstPriorityIndex = j; } } } } else { if(visInfo.framesSinceLastCheck > (kMinUnusedFramesBeforeEntryRemoved + visInfo.lastRequestedLatency)) { visInfo.flags |= eVF_Remove; } } } return numAdded; }
bool CPlayerVisTable::CanLocalPlayerSee(const SVisibilityParams& target, uint8 acceptableFrameLatency) { assert(acceptableFrameLatency < 128); //If this is too high there is the potential for the framesSinceLastCheck to overflow bool localPlayerCanSee = false; CryPrefetch(m_visTableEntries); VisEntryIndex visIndex = GetEntityIndexFromID(target.targetEntityId); #if ALLOW_VISTABLE_DEBUGGING m_numQueriesThisFrame++; #endif if(visIndex != -1) { SVisTableEntry& visInfo = m_visTableEntries[visIndex]; visInfo.lastRequestedLatency = ((visInfo.lastRequestedLatency + acceptableFrameLatency + 1) / 2); visInfo.flags |= eVF_Requested; if (target.queryParams & eVQP_UseCenterAsReference) { visInfo.flags |= eVF_CheckAgainstCenter; } visInfo.heightOffset = target.heightOffset; localPlayerCanSee = (target.queryParams & eVQP_IgnoreGlass) != 0 ? (visInfo.flags & eVF_VisibleThroughGlass) != 0 : (visInfo.flags & eVF_Visible) != 0; const bool checkAgainstSmoke = localPlayerCanSee && !(target.queryParams&eVQP_IgnoreSmoke); if(checkAgainstSmoke) { //Now check vs obscuring smoke grenades. These are created at runtime, randomly, // and have a short lifetime. Timeslicing the checks against them could render them // largely ineffective - Rich S Vec3 localPlayerPosn; GetLocalPlayerPosn(localPlayerPosn); IEntity * pEntity = gEnv->pEntitySystem->GetEntity(visInfo.entityId); if(pEntity) { if(!CSmokeManager::GetSmokeManager()->CanSeePointThroughSmoke(pEntity->GetPos(), localPlayerPosn)) { localPlayerCanSee = false; visInfo.flags &= ~(eVF_Visible | eVF_VisibleThroughGlass); } } } } else { SVisTableEntry& visInfo = m_visTableEntries[m_numUsedVisTableEntries]; visInfo.flags = eVF_Requested; if (target.queryParams & eVQP_UseCenterAsReference) { visInfo.flags |= eVF_CheckAgainstCenter; } visInfo.entityId = target.targetEntityId; visInfo.lastRequestedLatency = acceptableFrameLatency; visInfo.framesSinceLastCheck = acceptableFrameLatency; visInfo.heightOffset = target.heightOffset; localPlayerCanSee = false; m_numUsedVisTableEntries++; assert(m_numUsedVisTableEntries <= kMaxVisTableEntries); } return localPlayerCanSee; }
void CPlayerVisTable::Update(float dt) { const int numEntries = m_numUsedVisTableEntries; CryPrefetch(m_visTableEntries); //Flip the buffers m_currentBufferProcessing = 1 - m_currentBufferProcessing; m_currentBufferTarget = 1 - m_currentBufferTarget; Vec3 localPlayerPosn; GetLocalPlayerPosn(localPlayerPosn); //Iterate over all of the vis table entries and calculate the priorities int numAdded = AddVisTableEntriesToPriorityList(); //Iterate over all of the vis table entries for(int i = 0; i < numAdded; ++i) { const SVisTablePriority& visTableEntry = m_visTablePriorities[i]; DoVisibilityCheck(localPlayerPosn, *visTableEntry.visInfo, visTableEntry.visIndex); } const int kNumVistableEntries = m_numUsedVisTableEntries; for(int i = 0; i < kNumVistableEntries; i++) { m_visTableEntries[i].framesSinceLastCheck++; } #if ALLOW_VISTABLE_DEBUGGING if(g_pGameCVars->pl_debug_vistableIgnoreEntities) { UpdateIgnoreEntityDebug(); } if(g_pGameCVars->pl_debug_vistable) { const float white[] = {1.0f,1.0f,1.0f,1.0f}; const int kNumUsedVistableEntries = m_numUsedVisTableEntries; VisEntryIndex worstIndex = -1; int worstLatency = 0; for(int i = 0; i < kNumUsedVistableEntries; i++) { if((m_visTableEntries[i].flags & eVF_Requested) && !(m_visTableEntries[i].flags & eVF_Remove) && (m_visTableEntries[i].framesSinceLastCheck > worstLatency)) { worstLatency = m_visTableEntries[i].framesSinceLastCheck; worstIndex = i; } } int assertAfterThisManyFrames = g_pGameCVars->g_assertWhenVisTableNotUpdatedForNumFrames; if (worstLatency >= assertAfterThisManyFrames && worstIndex > 0 && worstIndex < kNumUsedVistableEntries) { IEntity * entity = gEnv->pEntitySystem->GetEntity(m_visTableEntries[worstIndex].entityId); CRY_ASSERT_MESSAGE(false, string().Format("%u frames have passed since last check of vis-table element %d (entity %d = %s \"%s\") flags=%u", m_visTableEntries[worstIndex].framesSinceLastCheck, worstIndex, m_visTableEntries[worstIndex].entityId, entity ? entity->GetClass()->GetName() : "NULL", entity ? entity->GetName() : "NULL", m_visTableEntries[worstIndex].flags)); } gEnv->pRenderer->Draw2dLabel(20.f, 500.f, 1.5f, white, false, "VistableInfo:\n Num Linetests this frame: %d\n Num queries this frame: %d\n Worst latency: %d", m_numLinetestsThisFrame, m_numQueriesThisFrame, worstLatency); if (g_pGameCVars->pl_debug_vistable == 2) { m_debugDraw.Update(); } } m_numQueriesThisFrame = 0; #endif m_numLinetestsThisFrame = 0; ClearRemovedEntities(); }