// renders visible wallmarks of specified pass type (pre or post, which is relevant in deferred context)
void VWallmarkManager::RenderProjectedWallmarks(VPassType_e ePassType)
{
  INSERT_PERF_MARKER_SCOPE("Wallmark Rendering (VWallmarkManager::RenderProjectedWallmarks)");

  const int iWallmarkCount = m_AllProjectedWallmarks.Count();
  IVisVisibilityCollector_cl *pVisCollector = Vision::Contexts.GetCurrentContext()->GetVisibilityCollector();
  if (!pVisCollector || !iWallmarkCount)
    return;

  const VisStaticGeometryInstanceCollection_cl *pGeoInstances = pVisCollector->GetVisibleStaticGeometryInstances();

  VisStaticGeometryInstance_cl::ResetTags();
  pGeoInstances->TagEntries();
  VisStaticGeometryInstanceCollection_cl &targetGiCollection = m_TempGeoInstanceCollection;

  VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext();
  VisRenderContext_cl *pLODContext = pContext->GetLODReferenceContext();
  hkvVec3 vLODPos = pLODContext ? pLODContext->GetCamera()->GetPosition() : pContext->GetCamera()->GetPosition();

  unsigned int iContextFilter = pContext->GetRenderFilterMask();
  const VisFrustum_cl *pFrustum = pVisCollector->GetBaseFrustum();

  int i;
  for (i=0;i<iWallmarkCount;i++)
  {
    VProjectedWallmark *pProjWallmark = m_AllProjectedWallmarks.GetAt(i);
    if ((pProjWallmark->GetVisibleBitmask() & iContextFilter)==0 || (ePassType & pProjWallmark->m_ePassType) == 0)
      continue;
    pProjWallmark->PrepareForRendering();
    const VisStaticGeometryInstanceCollection_cl &wmGiList = pProjWallmark->GetStaticGeometryCollection();  

#ifdef HK_DEBUG
    const int iNum = wmGiList.GetNumEntries();
    for (int j=0;j<iNum;j++)
    {
      VisStaticGeometryInstance_cl *pInst = wmGiList.GetEntry(j);
      VASSERT_MSG(pInst && (pInst->GetGeometryType()==STATIC_GEOMETRY_TYPE_MESHINSTANCE || pInst->GetGeometryType()==STATIC_GEOMETRY_TYPE_TERRAIN), "The wallmark conains invalid primitive references")
    }
#endif

    // clip against its bounding box (primitive visibility might overestimate visible parts)
    const hkvAlignedBBox &bbox = pProjWallmark->GetBoundingBox();
    if (pProjWallmark->m_fFarClipDistance>0.f && pProjWallmark->m_fFarClipDistance<bbox.getDistanceTo(vLODPos))
      continue;
    if (pFrustum && !pFrustum->Overlaps(bbox))
      continue;

    const int iGeomFilter = pProjWallmark->GetGeometryTypeFilterMask();
    if (iGeomFilter&PROJECTOR_AFFECTS_STATICMESHES)
    {
      // standard geometry
      targetGiCollection.Clear();
      wmGiList.GetTaggedEntriesOfType(targetGiCollection,STATIC_GEOMETRY_TYPE_MESHINSTANCE);
      if (targetGiCollection.GetNumEntries())
      {
        // render the static geometry instances using lightmapped or non-lightmapped shader
        VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_MESHINSTANCE);
        Vision::RenderLoopHelper.RenderStaticGeometryWithShader(targetGiCollection, *pShader);
      }
    }

    if (iGeomFilter&PROJECTOR_AFFECTS_TERRAIN)
    {
      // terrain geometry (different shader)
      targetGiCollection.Clear();
      wmGiList.GetTaggedEntriesOfType(targetGiCollection,STATIC_GEOMETRY_TYPE_TERRAIN);
      if (targetGiCollection.GetNumEntries()>0)
      {
        // render the static geometry instances using lightmapped or non-lightmapped shader
        VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_TERRAIN);
        if (pShader)
          Vision::RenderLoopHelper.RenderStaticGeometryWithShader(targetGiCollection, *pShader);
      }
    }

    // entities
    if (iGeomFilter&PROJECTOR_AFFECTS_ENTITIES)
    {
      const VisEntityCollection_cl *pVisibleEntities = pVisCollector->GetVisibleEntities();
      const unsigned int iInfluenceMask = pProjWallmark->GetInfluenceBitmask();
      m_TempEntityCollection.Clear();
      const int iEntCount = pVisibleEntities->GetNumEntries();
      for (int j=0;j<iEntCount;j++)
      {
        VisBaseEntity_cl *pEntity = pVisibleEntities->GetEntry(j);
        if (pEntity==NULL || (pEntity->GetVisibleBitmask()&iInfluenceMask)==0)
          continue;
        const hkvAlignedBBox &entityBox(*pEntity->GetCurrentVisBoundingBoxPtr());
        if (!entityBox.overlaps(bbox))
          continue;
        m_TempEntityCollection.AppendEntry(pEntity);
      }
      if (m_TempEntityCollection.GetNumEntries()>0)
      {
        VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_MESHINSTANCE); // we can use this shader - VS skinning is used implicitly
        Vision::RenderLoopHelper.RenderEntitiesWithShader(m_TempEntityCollection, *pShader);
      }
    }

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


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