void VCoronaManager::RenderAllVisibleCoronas() { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); // Determine relevant render context and visibility collector IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (!pVisCollector) return; VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext(); if (pOQContext != NULL) pContext = pOQContext; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; INSERT_PERF_MARKER_SCOPE("VCoronaManager::RenderAllVisibleCoronas"); VISION_PROFILE_FUNCTION(PROFILING_CORONA_RENDER); // Force for the queries to finish so they are available in this frame. if (m_bTeleportedLastFrame && m_bForceQueryOnTeleport) { UpdateCoronas(VCUF_UPDATE | VCUF_FORCE_FETCH | VCUF_USE_OC_CONTEXT); } // Ensure size of corona state structure. int iContextIndex = pContext->GetNumber(); if (iContextIndex + 1 > m_State.GetSize()) m_State.SetSize(iContextIndex + 1, -1); VCoronaRenderContextState& state = m_State[iContextIndex]; int iCapacity = m_Instances.GetCapacity(); state.EnsureSize(iCapacity); const int iCoronasToRender = state.m_Candidates.GetSize(); // Sort candidates by texture? VTextureObject* pTexture = NULL; // Render all corona components Vision::RenderLoopHelper.BeginMeshRendering(); Vision::RenderLoopHelper.AddMeshStreams(m_spBillboardMesh,VERTEX_STREAM_POSITION); for (int i=0; i < iCoronasToRender; ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); if (coronaCandidate.m_fCurrentVisibility > 0.0f) { RenderCorona (coronaCandidate, pTexture); } } Vision::RenderLoopHelper.EndMeshRendering(); m_bTeleportedLastFrame = (pContext->GetCamera()->GetLastTeleported() >= pContext->GetLastRenderedFrame()); #endif }
void VCoronaManager::UpdateCoronas(int iCoronaUpdateFlags) { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); if ((iCoronaUpdateFlags & VCUF_USE_OC_CONTEXT) > 0) { // Determine relevant render context and visibility collector IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (!pVisCollector) return; VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext(); if (pOQContext != NULL) pContext = pOQContext; } if (pContext == NULL) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; // Get bitmask for this context. unsigned int iRenderFilterMask = pContext->GetRenderFilterMask(); // get the collection of visible lights. IVisVisibilityCollector_cl* pVisCollector = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisCollector == NULL) return; VISION_PROFILE_FUNCTION(PROFILING_CORONA_UPDATE); // Get multi-sampling mode unsigned int iTexelsPerPixel = 1; VTextureObject* pDepthTex = pContext->GetDepthStencilTarget(); if(pDepthTex == NULL) { // If no depth stencil target is available, we might work without a renderer node and we're in the main context if(Vision::Renderer.GetCurrentRendererNode() == NULL && pContext == VisRenderContext_cl::GetMainRenderContext()) { // In this case get the multi-sampling type from the video config as it's used to set the actual backbuffer settings // where the main context will render to iTexelsPerPixel = hkvMath::Max(1, 1 << ((int)Vision::Video.GetCurrentConfig()->m_eMultiSample)); } } else if (pDepthTex->GetTextureType() == VTextureLoader::Texture2D) { iTexelsPerPixel = hkvMath::Max(1u, ((VisRenderableTexture_cl*)pDepthTex)->GetConfig()->m_iMultiSampling); } const VisLightSrcCollection_cl* pVisibleLights = pVisCollector->GetVisibleLights(); int iCandidates = 0; if (pVisibleLights != NULL) iCandidates = pVisibleLights->GetNumEntries(); // Ensure size of coronas state structure. int iContextIndex = pContext->GetNumber(); if (iContextIndex + 1 > m_State.GetSize()) m_State.SetSize(iContextIndex + 1, -1); VCoronaRenderContextState& state = m_State[iContextIndex]; int iCapacity = m_Instances.GetCapacity(); state.EnsureSize(iCapacity); // Add visible lights with a lens flare component to the candidate list for this frame if ((iCoronaUpdateFlags & VCUF_ADD) > 0) { for (int iCandidate = 0; iCandidate < iCandidates; ++iCandidate) { VisLightSource_cl* pLight = pVisibleLights->GetEntry(iCandidate); if (pLight) { VCoronaComponent *pComponent = pLight->Components().GetComponentOfBaseType<VCoronaComponent>(); if (pComponent != NULL && pComponent->IsEnabled() && !state.IsBitSet(pComponent->m_iIndex)) { // The component is not in m_Candidates yet, so we check whether it is a valid candidate bool bIsLightOnScreen = pComponent->IsValidCandidate(pContext); if (bIsLightOnScreen) { state.SetBit(pComponent->m_iIndex); pContext->SetPixelCounterResult(pComponent->m_CoronaPixelCounter.GetNumber(), 0); state.m_Candidates.Append(pComponent); } } } } } // Forces the retrieval all pending queries. pContext->FetchPixelCounterTestResults( (iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0 ); // Retrieve Queries and update status of lens flares if ((iCoronaUpdateFlags & VCUF_UPDATE) > 0) { for (int i=0; i < state.m_Candidates.GetSize(); ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; if (!pCorona || !pCorona->IsEnabled()) continue; if (pCorona->GetOwner()) { // Retrieve occlusion results of the last query unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); bool bRes = !pContext->IsPixelCounterQueryInProgress(iElementIndex); // Reschedule query if the old on could be retrieved or if a teleport forces us to re-query everything. if (bRes | ((iCoronaUpdateFlags & VCUF_FORCE_SCHEDULE) > 0) ) pContext->SchedulePixelCounterTest(iElementIndex); unsigned int iDrawnPixels = pContext->GetPixelCounterResult(iElementIndex) / iTexelsPerPixel; float fVisibility = (float)iDrawnPixels / ((int)pCorona->QueryRadius * (int)pCorona->QueryRadius * 4); // ATI fix for random insanely high return values. if (iDrawnPixels > ((unsigned int)pCorona->QueryRadius * 2 + 1) * ((unsigned int)pCorona->QueryRadius * 2 + 1)) { fVisibility = coronaCandidate.m_fLastVisibilityQuery; } if ((iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0) { // Force lens flare visibility to the current query value. coronaCandidate.m_fCurrentVisibility = fVisibility; coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else if (!m_bTeleportedLastFrame) { coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else { // if we were teleported, the last frame's query results must be invalidated coronaCandidate.m_fCurrentVisibility = 0.0f; coronaCandidate.m_fLastVisibilityQuery = 0.0f; } } } } // Removes coronas that are outside the frustum and no longer visible. if ((iCoronaUpdateFlags & VCUF_REMOVE) > 0) { for (int i=0; i < state.m_Candidates.GetSize();) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); // If the visibility reached zero and the corona is no longer potentially visible it is removed from the list if (!pCorona->IsEnabled() || !pCorona->GetOwner() || (pCorona->GetVisibleBitmask() & iRenderFilterMask) == 0 || (((VisLightSource_cl*)pCorona->GetOwner())->GetVisibleBitmask() & iRenderFilterMask) == 0 || ( coronaCandidate.m_fCurrentVisibility == 0.0f && !pCorona->IsValidCandidate(pContext) ) ) { state.RemoveBit(pCorona->m_iIndex); state.m_Candidates.SetAt(i, state.m_Candidates.GetAt(state.m_Candidates.GetSize()-1) ); state.m_Candidates.RemoveAt(state.m_Candidates.GetSize() -1); // Reset cache to zero, so we don't see the lens flare once it enters the frustum again. pContext->SetPixelCounterResult(iElementIndex, 0); } else { ++i; } } } #endif }