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();
}