void VPostProcessTranslucencies::Execute()
{
  INSERT_PERF_MARKER_SCOPE("VPostProcessTranslucencies");

  VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext();
  IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector();
  VASSERT(pVisCollector != NULL);

  const VisEntityCollection_cl *pVisibleForeGroundEntities = pVisCollector->GetVisibleForeGroundEntities();

  m_VisibilityObjectCollector.HandleVisibleVisibilityObjects();

#ifndef _VISION_MOBILE
  RenderingOptimizationHelpers_cl::SetShaderPreference(96);
#endif

  // Get a pointer to the collection of visible mesh buffer objects
  const VisMeshBufferObjectCollection_cl *pVisibleMeshBuffer = &m_VisibilityObjectCollector.GetMeshBufferObjectCollection();

  // Get a pointer to the collection of visible particle groups
  const VisParticleGroupCollection_cl *pVisibleParticleGroups = &m_VisibilityObjectCollector.GetParticleGroupCollection();

  // Mask out entities which are "always in foreground"
  MaskOutForegroundEntities(*pVisibleForeGroundEntities);

  if (pVisCollector->GetInterleavedTranslucencySorter() == NULL)
  {
    // --- Traditional transparency sorting (default)
    const VisStaticGeometryInstanceCollection_cl *pVisibleTransparentGeoInstances = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass);
    const VisEntityCollection_cl *pVisibleEntities = pVisCollector->GetVisibleEntitiesForPass(VPT_TransparentPass);

    VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_GEOMETRY, true);

    // render transparent pass surface shaders on translucent static geometry instances
    Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleTransparentGeoInstances, VPT_TransparentPass);

    VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_ENTITIES, true);

    // Render transparent pass shaders on entities
    DrawEntitiesShaders(*pVisibleEntities, VPT_TransparentPass);

    VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_TRANSPARENT_PASS_GEOMETRY, true);

    VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_DECALS, true);

    RenderParticles(pVisibleMeshBuffer, pVisibleParticleGroups);
  }
  else
  {
    // --- Interleaved transparency sorting
    pVisCollector->GetInterleavedTranslucencySorter()->OnRender(pVisCollector, true);
  }

  // Render visible foreground entities (see DrawForegroundEntities)
  DrawTransparentForegroundEntities(*pVisibleForeGroundEntities);

  // Coronas and flares will be still rendered after the other interleaved sorted objects were rendered (lensflare and coronas don't must be always rendered "on top") 
  VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_CORONAS_AND_FLARES, true);
}
/////////////////////////////////////////////////////////////////////////////
// RenderAllShadows : render all shadow instances
/////////////////////////////////////////////////////////////////////////////
void VBlobShadowManager::RenderAllShadows()
{
    // if enabled, a 2D bounding box is additionally used for clipping, which saves a lot of fillrate!

    // TODO: PSP2 - fix 2d clipping
#if defined(_VISION_PSP2)
    static bool bClipScissor = false;
#else
    static bool bClipScissor = true;
#endif
    VisFrustum_cl viewFrustum;
    IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector();
    if (pVisColl==NULL || pVisColl->GetBaseFrustum()==NULL)
        return;
    viewFrustum.CopyFrom((VisFrustum_cl&)*pVisColl->GetBaseFrustum());

    // render all shadows
    VISION_PROFILE_FUNCTION(PROFILING_BS_OVERALL);

    // get the collection of visible (opaque) primitives. For each shadow instance determine
    // the primitives in this list, which intersect with the shadow box
    // (we do not want to render primitives that are not visible)
    const VisStaticGeometryInstanceCollection_cl *pVisibleGeom = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass);

    VRectanglef clipRect(false);
    VRectanglef screenRect(0.f,0.f,(float)Vision::Video.GetXRes(),(float)Vision::Video.GetYRes());
    hkvVec3 vBoxCorner[8];
    hkvVec2 vCorner2D(false);

    // now render the shadows:
    FOR_ALL_SHADOWS

    if (pShadow->GetOwner())
        pShadow->SetBoundingBoxFromOwnerProperties();

    // shadow box visible?
    if (!viewFrustum.Overlaps(pShadow->m_ShadowBox))
        continue;

    // build 2D bounding box for scissor clipping
    if (bClipScissor)
    {
        VISION_PROFILE_FUNCTION(PROFILING_BS_SCISSORRECT);
        clipRect.Reset();
        pShadow->m_ShadowBox.getCorners(vBoxCorner);
        for (int i=0; i<8; i++)
        {
            // if one vertex is behind camera, do not use clipping
            if (!Vision::Contexts.GetCurrentContext()->Project2D(vBoxCorner[i],vCorner2D.x,vCorner2D.y))
            {
                Vision::RenderLoopHelper.SetScissorRect(NULL);
                goto render_shadow;
            }
            clipRect.Add(vCorner2D);
        }
        VASSERT(clipRect.IsValid());
        clipRect = clipRect.GetIntersection(screenRect);
        if (!clipRect.IsValid())
            continue; // do not render shadows at all if rect is outside the screen
        Vision::RenderLoopHelper.SetScissorRect(&clipRect);
    }

render_shadow:

    // get the visible primitives in the shadow bounding box
    {
        VISION_PROFILE_FUNCTION(PROFILING_BS_DETERMINE_PRIMS);
        // affected static geometry:
        shadowGeom.Clear();
        pVisibleGeom->DetermineEntriesTouchingBox(pShadow->m_ShadowBox,shadowGeom);
    }

    // split into geometry types:
    if (!shadowGeom.GetNumEntries())
        continue;

    const VisStaticGeometryType_e relevantTypes[2] = {STATIC_GEOMETRY_TYPE_MESHINSTANCE,STATIC_GEOMETRY_TYPE_TERRAIN};

    // two relevant geometry types:
    for (int iType=0; iType<2; iType++)
    {
        shadowGeomOfType.Clear();
        shadowGeom.GetEntriesOfType(shadowGeomOfType,relevantTypes[iType]);
        VCompiledTechnique *pFX = GetDefaultTechnique(relevantTypes[iType]);
        if (shadowGeomOfType.GetNumEntries()==0 || pFX==NULL)
            continue;

        // for all the shader in the projection effect (usually 1 shader), render the primitive collection
        const int iShaderCount = pFX->GetShaderCount();

        for (int j=0; j<iShaderCount; j++)
        {
            VBlobShadowShader *pShader = (VBlobShadowShader *)pFX->GetShader(j);

            {   // code block for easier profiling
                VISION_PROFILE_FUNCTION(PROFILING_BS_PREPARE_SHADER);
                // prepare the shader, i.e. setup shadow specific projection planes, colors etc.
                pShader->UpdateShadow(pShadow);
            }
            {   // code block for easier profiling
                VISION_PROFILE_FUNCTION(PROFILING_BS_RENDER_PRIMS);
                Vision::RenderLoopHelper.RenderStaticGeometryWithShader(shadowGeomOfType,*pShader);
            }
        }
    }


}
// TODO: This doesn't handle opaque fullbright surfaces correctly yet, and translucent fullbright surfaces are simply ignored.
void MirrorRenderLoop_cl::OnDoRenderLoop(void *pUserData)
{
  INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::OnDoRenderLoop");

#if defined (WIN32) || defined (_VISION_XENON) || defined (_VISION_PS3) || defined(_VISION_PSP2) || defined(_VISION_WIIU)
  if (Vision::Editor.GetIgnoreAdvancedEffects())
  {
    // force a black reflection because it won't work with orthographic views
    Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, V_RGBA_BLACK);
    return;
  }
#endif

  VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext();

  const int iRenderFlags = pContext->GetRenderFlags();

  const float fFarClipDist = m_pMirror->GetActualFarClipDistance();

  const VFogParameters &fog = Vision::World.GetFogParameters();
  VColorRef clearColor = (fog.depthMode != VFogParameters::Off) ? fog.iDepthColor : Vision::Renderer.GetDefaultClearColor();
  Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, clearColor);

  // set the oblique clipping plane...
  pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ());

  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass;
  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass;
  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass;
  const VisEntityCollection_cl *pVisEntities;


  // === Visibility Determination ===

  IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector();
  if (pVisColl == NULL)
    return;
  const VisVisibilityObjectCollection_cl *pVisObjectCollection = pVisColl->GetVisibleVisObjects();

  hkvAlignedBBox box;
  int iVoCount = m_pMirror->GetVisibilityObjectCount();
  int iFrustumCount = 0;
  bool bUseCommonFrustum = false;

  // === Determine Scissor Rect ===
  hkvVec2 vMinScreenSpace, vMaxScreenSpace;
  const hkvAlignedBBox &worldSpaceBox = m_pMirror->GetBoundingBox();

  hkvVec3 vCorners[8];
  worldSpaceBox.getCorners (vCorners);

  VRectanglef scissorRect;
  bool bUseScissorRect = true;
  for (int i=0; i<8; i++)
  {
    float x2d, y2d;
    BOOL bInFrontOfCamera = pContext->Project2D(vCorners[i], x2d, y2d);
    if (bInFrontOfCamera)
    {
      scissorRect.Add(hkvVec2(x2d, y2d));
    }
    else
    {
      bUseScissorRect = false;
      break;
    }
  }

  if (bUseScissorRect)
    Vision::RenderLoopHelper.SetScissorRect(&scissorRect);

  for (int iVo = 0; iVo < iVoCount; iVo++)
  {
    VisVisibilityObject_cl *pVisObj = m_pMirror->GetVisibilityObject(iVo);
    if (pVisObj != NULL && pVisObj->WasVisibleInAnyLastFrame())
    {
      if (iFrustumCount <= MAX_SEPARATE_FRUSTA)
      {
        const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox();
        box.expandToInclude(voBox);
        if (m_Frustum[iFrustumCount].Set(pContext->GetCamera()->GetPosition(), voBox, true, fFarClipDist))
        {
          iFrustumCount++;
        }
        else
        {
          bUseCommonFrustum = true;
        }
      }
      else
      {
        const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox();
        box.expandToInclude(voBox);
        bUseCommonFrustum = true;
      }
    }
  }

  if (bUseCommonFrustum)
  {
    iFrustumCount = 1;
    if (!m_Frustum[0].Set(pContext->GetCamera()->GetPosition(), box, true, fFarClipDist))
      iFrustumCount = 0;
  }

  if (iFrustumCount>0)
  {
    for (int i=0; i<iFrustumCount; i++)
    {
      m_visiblePrimaryOpaquePassGeoInstances.Clear();
      m_visibleSecondaryOpaquePassGeoInstances.Clear();
      m_visibleTransparentOpaquePassGeoInstances.Clear();
      m_visEntities.Clear();
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visiblePrimaryOpaquePassGeoInstances);
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleSecondaryOpaquePassGeoInstances);
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleTransparentOpaquePassGeoInstances);
      pVisColl->GetVisibleEntities()->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visEntities);
      if (iFrustumCount == 1)
        break;
      m_visiblePrimaryOpaquePassGeoInstances.TagEntries();
      m_visibleSecondaryOpaquePassGeoInstances.TagEntries();
      m_visibleTransparentOpaquePassGeoInstances.TagEntries();
      m_visEntities.TagEntries();
    }
    if (iFrustumCount > 1)
    {
      m_visiblePrimaryOpaquePassGeoInstances.Clear();
      m_visibleSecondaryOpaquePassGeoInstances.Clear();
      m_visibleTransparentOpaquePassGeoInstances.Clear();
      m_visEntities.Clear();
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->GetTaggedEntries(m_visiblePrimaryOpaquePassGeoInstances);
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->GetTaggedEntries(m_visibleSecondaryOpaquePassGeoInstances);
      pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->GetTaggedEntries(m_visibleTransparentOpaquePassGeoInstances);
      pVisColl->GetVisibleEntities()->GetTaggedEntries(m_visEntities);
    }
    pVisibleGeoInstancesPrimaryOpaquePass = &m_visiblePrimaryOpaquePassGeoInstances;
    pVisibleGeoInstancesSecondaryOpaquePass = &m_visibleSecondaryOpaquePassGeoInstances;
    pVisibleGeoInstancesTransparentPass = &m_visibleTransparentOpaquePassGeoInstances;
    pVisEntities = &m_visEntities;
  }
  else
  {
    pVisibleGeoInstancesPrimaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass);
    pVisibleGeoInstancesSecondaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass);
    pVisibleGeoInstancesTransparentPass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass);
    pVisEntities = pVisColl->GetVisibleEntities();
  }

  // === End Visibility Determination ===

  if (m_pMirror->GetExecuteRenderHooks())
  {
    VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY);
    Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data);
  }

  // Render opaque static geometry
  VASSERT(m_spDefaultLightMapping->m_Shaders.Count()==1);

  TRIGGER_MIRROR_HOOK(VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY)
  VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode;
  DrawStaticGeometry(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass);
  DrawStaticGeometry(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass);

  // Render entities
  const VisEntityCollection_cl *pEntities = pVisEntities;
  int iCount = pEntities->GetNumEntries();
  VASSERT(m_spDefaultLightGrid->m_Shaders.Count()==1);
  //VCompiledShaderPass *pLightgridShader = m_spDefaultLightGrid->m_Shaders.GetAt(0);
  int i;
  //bool bUseSimpleShader = shaderMode==VisMirror_cl::AlwaysSimple;

  Vision::RenderLoopHelper.BeginEntityRendering();

  for (i=0;i<iCount;i++)
  { 
    VisBaseEntity_cl *pEnt = pEntities->GetEntry(i);

//    Vision::RenderLoopHelper.TrackLightGridInfo(pEnt);  // important: need to be done in RenderEntityWithSurfaceShaderList

    //if (bUseSimpleShader)
    //{
    //  Vision::RenderLoopHelper.RenderEntityWithShaders(pEnt,1,&pLightgridShader);
    //}
    //else
    {
      VisDrawCallInfo_t surfaceShaderList[RLP_MAX_ENTITY_SURFACES];
      VDynamicMesh *pMesh = pEnt->GetMesh();
      VisSurface_cl **ppSurfaces = pEnt->GetSurfaceArray();
      int iNumSubmeshes = pMesh->GetSubmeshCount();
      for (int j=0; j<iNumSubmeshes; j++)
      {
        VisDrawCallInfo_t &info(surfaceShaderList[j]);
        VBaseSubmesh* pSubmesh = pMesh->GetSubmesh(j);
        VisSurface_cl* pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex];
        info.Set(pSubmesh, pSurface, GetMirrorShader (pSurface, shaderMode));
      }

      Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEnt, iNumSubmeshes, surfaceShaderList);
    }
  }

  Vision::RenderLoopHelper.EndEntityRendering();

  // Render Sky
  if (VSky::IsVisible())
  {
    // The sky has to be rendered without oblique clipping
    pContext->SetCustomProjectionMatrix(NULL);
    Vision::RenderLoopHelper.RenderSky();
    // set the oblique clipping plane after sky...
    pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ());
  }

  if (m_pMirror->GetExecuteRenderHooks())
  {
    VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_OCCLUSION_TESTS);
    Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data);
  }

  // Render Coronas / Lens Flares
  VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_CORONAS_AND_FLARES);
  Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data);
  TRIGGER_MIRROR_HOOK(VRH_PRE_OCCLUSION_TESTS)  

  if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_OCCLUSIONQUERY)
    Vision::RenderLoopHelper.PerformHardwareOcclusionQuery();

  if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER)
    Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery();

  DrawDynamicLight();

  TRIGGER_MIRROR_HOOK(VRH_DECALS)
  TRIGGER_MIRROR_HOOK(VRH_CORONAS_AND_FLARES)

  TRIGGER_MIRROR_HOOK(VRH_PRE_TRANSPARENT_PASS_GEOMETRY)
  DrawStaticGeometry(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass);
  TRIGGER_MIRROR_HOOK(VRH_POST_TRANSPARENT_PASS_GEOMETRY)

  if (bUseScissorRect)
    Vision::RenderLoopHelper.SetScissorRect(NULL);
}
void VMobileForwardRenderLoop::OnDoRenderLoop(void *pUserData)
{
  INSERT_PERF_MARKER_SCOPE("VMobileForwardRenderLoop::OnDoRenderLoop");

  m_iFrameCounter++; // just for arbitrary custom purposes

#ifdef WIN32
  // vForge specific:
  if (Vision::RenderLoopHelper.GetReplacementRenderLoop())
  {
    // render with this render-loop instead
    Vision::RenderLoopHelper.GetReplacementRenderLoop()->OnDoRenderLoop(pUserData);
    return;
  }
#endif

  m_pShaderProvider = Vision::GetApplication()->GetShaderProvider();
  VASSERT(m_pShaderProvider);
  m_pShaderProvider->ResetCache();

  VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext();
  IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector();
  if (pVisCollector==NULL)
    return; 

  const int iRenderFlags = pContext->GetRenderFlags();
  m_pCameraFrustum = pVisCollector->GetBaseFrustum(); 

  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass);
  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass);
  const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass);
  const VisEntityCollection_cl *pVisibleEntitiesPrimaryOpaquePass = pVisCollector->GetVisibleEntitiesForPass(VPT_PrimaryOpaquePass);
  const VisEntityCollection_cl *pVisibleEntitiesSecondaryOpaquePass = pVisCollector->GetVisibleEntitiesForPass(VPT_SecondaryOpaquePass);
  const VisEntityCollection_cl *pVisibleEntitiesTransparentPass = pVisCollector->GetVisibleEntitiesForPass(VPT_TransparentPass);
  const VisEntityCollection_cl *pVisibleForeGroundEntities = pVisCollector->GetVisibleForeGroundEntities();
  HandleVisibleVisibilityObjects();

  // Clear the screen
  if ((iRenderFlags&VIS_RENDERCONTEXT_FLAG_NO_CLEARSCREEN)==0)
  {
    const VFogParameters &fog = Vision::World.GetFogParameters();
    VColorRef clearColor = fog.depthMode != VFogParameters::Off ? fog.iDepthColor : Vision::Renderer.GetDefaultClearColor();
    Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, clearColor);
  }

  m_bHasRenderHookCallbacks = m_bTriggerCallbacks && Vision::Callbacks.OnRenderHook.HasCallbacks();

  // Get a pointer to the collection of visible mesh buffer objects
  const VisMeshBufferObjectCollection_cl *pVisibleMeshBuffer = &m_VisibilityObjectCollector.GetMeshBufferObjectCollection();

  // Get a pointer to the collection of visible particle groups
  const VisParticleGroupCollection_cl *pVisibleParticleGroups = &m_VisibilityObjectCollector.GetParticleGroupCollection();

  // Determine which lights have to rendered in the current frame
  DetermineRelevantLights();

  // Render all mesh buffer objects with the render order flag "VRH_PRE_RENDERING".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_RENDERING, m_bTriggerCallbacks);

  // Render all mesh buffer objects with the render order flag "VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY, m_bTriggerCallbacks);

  // Reset tags
  VisStaticGeometryInstance_cl::ResetTags();
  VisBaseEntity_cl::ResetTags();
  
  // Clear temporary collections for geometry that is lit by base pass light, but rendered in additive lighting pass
  m_AdditiveLitGeoInstanceCollection.Clear();
  m_AdditiveLitEntityCollection.Clear();

  // Prepare the initial lighting pass (one light collapsed with base lighting contribution)
  bool bUsesLightClippingVolume = false;
  IVShadowMapComponent *pShadowMap = PrepareLightingPass(m_pBasePassLight, true, bUsesLightClippingVolume);

  // Render lit geometry before actual base pass, whereby the geometry which has been rendered here will be tagged, in order
  // to avoid re-rendering later on. We first render static meshes lit base the base pass light, then static meshes not lit by the base pass light,
  // and then entities (with/without base pass light, respectively).
  {
    RenderLitGeometry(m_pBasePassLight, pShadowMap, true, bUsesLightClippingVolume, false, true);

    // Render all primary opaque pass surface shaders on opaque world geometry
    Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES); 

    // Render all mesh buffer objects with the render order flag "VRH_PRE_PRIMARY_OPAQUE_PASS_ENTITIES".
    RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_PRIMARY_OPAQUE_PASS_ENTITIES, m_bTriggerCallbacks);

    RenderLitGeometry(m_pBasePassLight, pShadowMap, true, bUsesLightClippingVolume, true, false);

    // Render all primary opaque pass shaders on entities (see "DrawEntitiesShaders")
    DrawEntitiesShaders(*pVisibleEntitiesPrimaryOpaquePass, VPT_PrimaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES);
  }

  // Finalize the initial pass
  FinalizeLightingPass(m_pBasePassLight, bUsesLightClippingVolume);

  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_SECONDARY_OPAQUE_PASS_GEOMETRY, m_bTriggerCallbacks);

  // Render static geometry instances for secondary opaque pass
  Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES);
  
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_SECONDARY_OPAQUE_PASS_ENTITIES, m_bTriggerCallbacks);

  // Render entities for secondary opaque pass
  DrawEntitiesShaders(*pVisibleEntitiesSecondaryOpaquePass, VPT_SecondaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES);

  // Start the hardware occlusion query. Note that this function always has to be called in render loops.
  // Also, the position of this call in the OnDoRenderLoop is important: The zBuffer contents at this stage of rendering will
  // act as occluders in the hardware occlusion queries.
  Vision::RenderLoopHelper.PerformHardwareOcclusionQuery();

  // Render sky
  Vision::RenderLoopHelper.RenderSky();

  // Render all mesh buffer objects with the render order flag "VRH_PRE_OCCLUSION_TESTS".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_OCCLUSION_TESTS, m_bTriggerCallbacks);

  Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery();

  // Render all mesh buffer objects with the render order flag "VRH_POST_OCCLUSION_TESTS".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_OCCLUSION_TESTS, m_bTriggerCallbacks);

  // Draw dynamic light 
  DrawDynamicLight();

  // Render all mesh buffer objects with the render order flag "VRH_PRE_TRANSPARENT_PASS_GEOMETRY".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_GEOMETRY, m_bTriggerCallbacks); 
  
  // Render transparent pass surface shaders on translucent lit world primitives
  Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass, VTF_IGNORE_TAGGED_ENTRIES);

  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_ENTITIES, m_bTriggerCallbacks);

  // Render transparent pass shaders on entities
  DrawEntitiesShaders(*pVisibleEntitiesTransparentPass, VPT_TransparentPass, VTF_IGNORE_TAGGED_ENTRIES);

  // Render all mesh buffer objects with the render order flag "VRH_POST_TRANSPARENT_PASS_GEOMETRY".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_TRANSPARENT_PASS_GEOMETRY, m_bTriggerCallbacks);

  // Render all mesh buffer objects and particle systems with the render order flag "VRH_DECALS".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_DECALS, m_bTriggerCallbacks);

  // Render all mesh buffer objects and particle systems with the render order flag "VRH_PARTICLES".
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PARTICLES, m_bTriggerCallbacks);

  // Render all mesh buffer objects with the render order flag "VRH_ADDITIVE_PARTICLES"
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_ADDITIVE_PARTICLES, m_bTriggerCallbacks);

  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_TRANSLUCENT_VOLUMES, m_bTriggerCallbacks);

  // Render visible foreground entities (see DrawForegroundEntities)
  DrawForegroundEntities(*pVisibleForeGroundEntities);

  // Render all mesh buffer objects with the render order flag "VRH_CORONAS_AND_FLARES"
  RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_CORONAS_AND_FLARES, m_bTriggerCallbacks);

  m_pShaderProvider = NULL;
}