void VLensFlareComponent::GetVariableAttributes(VisVariable_cl *pVariable, VVariableAttributeInfo &destInfo)
{
  // Check whether we need to display the OnlyVisibleInSpotLight property. It should be only visible when the owner is a spotlight
  if (!strcmp(pVariable->GetName(),"OnlyVisibleInSpotLight"))
  {
    VisLightSource_cl* pLight = (VisLightSource_cl*)GetOwner();
    if(pLight && pLight->GetType() == VIS_LIGHT_SPOTLIGHT)
      destInfo.m_bHidden = false;
    else
      destInfo.m_bHidden = true;
  }
}
void VLensFlareComponent::UpdateVisibility (float& fLastVisibilityQuery, float& fCurrentVisibility)
{
  // Make sure we are actually attached to an object
  if (GetOwner())
  {
    // Get Camera
    VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext();
    const hkvVec3 vCameraPos = pContext->GetCamera()->GetPosition();

    // Get Light
    VisLightSource_cl* pLight = (VisLightSource_cl*)GetOwner();
    hkvVec3 vPos;
    pLight->GetVirtualPosition( vPos, pContext );

    hkvVec3 vDist = vCameraPos - vPos;
    float fDist = vDist.getLength();
    float fFactor = 1.0f;

    // Distance FadeOut
    if (FadeOutEnd != 0 && FadeOutStart < FadeOutEnd)
    {
      if (fDist > FadeOutEnd)
      {
        fFactor = 0.0f;
      }
      else if (fDist > FadeOutStart)
      {
        fFactor = 1.0f - (fDist - FadeOutStart) / (FadeOutEnd - FadeOutStart);
      }
    }

    // Apply distance fade out
    fLastVisibilityQuery *= fFactor;

    // PreGlow/AfterGlow
    if (fLastVisibilityQuery > fCurrentVisibility)
    {
      float fSpeed = Vision::GetTimer()->GetTimeDifference() / ((PreGlowMS + 1) * 0.001f);
      fCurrentVisibility = hkvMath::Min(fCurrentVisibility + fSpeed, fLastVisibilityQuery);
    }
    else if (fLastVisibilityQuery < fCurrentVisibility)
    {
      float fSpeed = Vision::GetTimer()->GetTimeDifference() / ((AfterGlowMS + 1) * 0.001f);
      fCurrentVisibility = hkvMath::Max(fCurrentVisibility - fSpeed, fLastVisibilityQuery);
    }

    fCurrentVisibility = hkvMath::clamp(fCurrentVisibility, 0.0f, 1.0f);
  }
}
void VMobileForwardRenderLoop::DetermineRelevantLights()
{
  m_DynamicLightCollection.Clear();
  m_pBasePassLight = NULL;
  m_iBasePassLightPriority = 0;

  // Get all visible light sources
  IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector();
  if (pVisColl == NULL)
    return;
  const VisLightSrcCollection_cl *pLightSourceCollection = pVisColl->GetVisibleLights();
  if (pLightSourceCollection == NULL)
    return;

  unsigned int iNumLights = pLightSourceCollection->GetNumEntries();
  if (iNumLights == 0)
    return;
  
  VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext();
  const hkvVec3 &vCamPos = pContext->GetCamera()->GetPosition();

  for (unsigned i=0;i<iNumLights;i++)
  {
    VisLightSource_cl *pLight = pLightSourceCollection->GetEntry(i);

    // We are only interested in dynamic lights or static lights with attached shadow map component
    if ((!pLight->IsDynamic() && !GetCompatibleShadowMapComponent(pLight)) || pLight->GetRadius()<=HKVMATH_LARGE_EPSILON)  
      continue;

    const float fFade = pLight->GetMultiplier()*pLight->GetFadeWeight(vCamPos);
    if (fFade <= HKVMATH_LARGE_EPSILON)
      continue;

    // See which geometry types have to cast shadows
    int iReceiverFlags = GetLightReceiverFlags(pLight);

    // If nothing receives light from this light source, we can proceed to the next light.
    if (!iReceiverFlags)
      continue;

    // Find light with highest priority. This light will be rendered in the base pass, in contrast to all 
    // additional lights that are rendered additively after the base pass. The search ignores lights with 
    // attached light clipping volume, since light clipping volumes can't be rendered before the base pass.
    if (!pLight->HasClipVolumeComponent())
    {
      // get the light with highest priority (largest influence area in screen space combined with weighting factor)
      int iLightPriority = GetLightPriority(pLight);
      if (iLightPriority > m_iBasePassLightPriority)
      {
        m_pBasePassLight = pLight;
        m_iBasePassLightPriority = iLightPriority;
      }
    } 
   
    if (pLight->IsDynamic())
      m_DynamicLightCollection.AppendEntry(pLight); 
  }
}
bool VOcclusionQueryObjectPixelCounterLensFlare::Render(VOcclusionQuery &query, const hkvAlignedBBox &safeBox)
{
  if (m_pLensFlare != NULL && m_pLensFlare->GetOwner() != NULL)
  {
    SetState(VISQUERY_RENDERSTATE_BILLBOARD);
    
    VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext();

    VisLightSource_cl* pLight = (VisLightSource_cl*)m_pLensFlare->GetOwner();
    hkvVec3 vPos(hkvNoInitialization);
    pLight->GetVirtualPosition(vPos, pContext);

    hkvVec3 vCameraDir = pContext->GetCamera()->GetPosition() - vPos;
    vCameraDir /= hkvMath::Max(vCameraDir.getLength(), HKVMATH_LARGE_EPSILON);

    vPos += vCameraDir * m_pLensFlare->GetDepthBias();

    query.DoHardwareOcclusionTest_Billboard(&vPos.x, m_pLensFlare->GetCheckBlockSize());
    return true;
  }
  return false;
}
// Simplified version of dynamic light rendering for mirrors
void MirrorRenderLoop_cl::DrawDynamicLight()
{
  INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::DrawDynamicLight");

  // Some local variables for storing surfaces, shaders, surface shaders, and the like.
  VisDrawCallInfo_t SurfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS];
  VCompiledTechnique *pTechnique = NULL;

  VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode;

  // Get all visible light sources
  IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector();
  if (pVisColl == NULL)
    return;

  const VisLightSrcCollection_cl *pLightSourceCollection = pVisColl->GetVisibleLights();
  unsigned int i;
  unsigned int iNumLights = pLightSourceCollection->GetNumEntries();
  if (iNumLights == 0)
    return;

  // Set depth-stencil state
  VisRenderStates_cl::SetDepthStencilState(m_dynLightDefaultState);
  
  // For all visible lights...
  for (i=0; i<iNumLights; i++)
  {
    VisLightSource_cl *pLight = pLightSourceCollection->GetEntry(i);
    // We're only interested in dynamic lights
    if (!pLight->IsDynamic()) 
      continue;

    // Clear the collections of geo instances and entities, since we want to build them from scratch for each light
    s_LitEntityCollection.Clear();
    s_LitGeoInstanceCollection.Clear();

    // See which geometry types have to cast shadows
    int iReceiverFlags = GetLightReceiverFlags(pLight);

    // If nothing receives light from this light source, we can proceed to the next light.
    if (!iReceiverFlags)
      continue;

    // ***************** Create lists of illuminated scene elements *****************

    // If no shadows are cast, we simply illuminate all visible geometry within the range (spherical) of the light.
    VisEntityCollection_cl *pEntColl = NULL;
    if (iReceiverFlags & VIS_LIGHTSRCVIS_MODELS)
      pEntColl = &s_LitEntityCollection;
    VisStaticGeometryInstanceCollection_cl *pGeoInstanceColl = NULL;
    if (iReceiverFlags & VIS_LIGHTSRCVIS_PRIMITIVES)
    {
      pGeoInstanceColl = &s_LitGeoInstanceCollection;
    }

    Vision::RenderLoopHelper.GetVisibleGeometryInLightsourceRange(pGeoInstanceColl, pEntColl, NULL, *pLight);

    // For all illuminated entities: Render a dynamic lighting pass now.
    if (pLight->GetLightInfluenceBitMaskEntity())
    {
      int j;
      
      int iNumLitEntities = s_LitEntityCollection.GetNumEntries();

      Vision::RenderLoopHelper.BeginEntityRendering();

      for (j=0; j<iNumLitEntities; j++)
      {
        VisBaseEntity_cl *pEntity = s_LitEntityCollection.GetEntry(j);
        // Ignore foreground entities (they don't trivially support additive lighting)
        if (pEntity->IsObjectAlwaysInForegroundEnabled())
          continue;
        if (!(pEntity->GetLightInfluenceBitMask() & pLight->GetLightInfluenceBitMaskEntity()))
          continue;
        if (!pVisColl->IsEntityVisible(pEntity))
          continue;
          
        VDynamicMesh *pMesh = pEntity->GetMesh();
          
        // Get list of all the surfaces in the model
        int iNumSubmeshes = pMesh->GetSubmeshCount();
        int iNumSurfaceShaders = 0;
        VisSurface_cl **ppSurfaceArray = pEntity->GetSurfaceArray();

        // For all the surfaces...
        for (int k=0; k<iNumSubmeshes; k++)
        {
          VDynamicSubmesh *pSubmesh = pMesh->GetSubmesh(k);
          VASSERT(pSubmesh != NULL);
          VisSurface_cl* pSurface = &m_dummySurface; 
          VisSurface_cl* pMeshSurface = pSubmesh->m_pSurface;
          VASSERT(pMeshSurface != NULL);

          bool bHasManualTemplateShaderAssignment = pMeshSurface->GetShaderMode() == VisSurface_cl::VSM_Template 
            && pMeshSurface->GetMaterialTemplate() != NULL && pMeshSurface->GetMaterialTemplate()->HasManualAssignment();

          if (shaderMode == VisMirror_cl::AlwaysSurfaceShaders || 
            (shaderMode == VisMirror_cl::SimpleForAUTO && ( (pMeshSurface->GetShaderMode() == VisSurface_cl::VSM_Manual) || bHasManualTemplateShaderAssignment) ) )
          {
            pSurface = ppSurfaceArray[pSubmesh->m_iMaterialIndex]; // use the real surface
          }
          pTechnique = Vision::GetApplication()->GetShaderProvider()->GetDynamicLightShader(pLight, pSurface, true);
          if (pTechnique==NULL)
            continue;
            
          VisDrawCallInfo_t &info(SurfaceShaderList[iNumSurfaceShaders++]);
          info.Set(pSubmesh, pSurface, pTechnique->m_Shaders.GetAt(0));
        }
        // Finally, render the entity with a surface shader list.
        if (iNumSurfaceShaders>0)
          Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, SurfaceShaderList);
      }

      Vision::RenderLoopHelper.EndEntityRendering();
    }

    // For all illuminated world primitives: Render a dynamic lighting pass now
    if (pLight->GetLightInfluenceBitMaskWorld() > 0)
    {
      // For all illuminated static geometry instances: Render a dynamic lighting pass now.
      int iNumLitGeoInstances = s_LitGeoInstanceCollection.GetNumEntries();

      s_RenderGeoInstanceCollection.Clear();

      // Render illuminated geometry instances. 
      for (int j=0; j < iNumLitGeoInstances; j++)
      {
        VisStaticGeometryInstance_cl *pGI = s_LitGeoInstanceCollection.GetEntry(j);

        if (pGI->GetSurface()==NULL || pGI->GetSurface()->IsFullbright())
          continue;
       
        // We have to append the primitive to our collection
        s_RenderGeoInstanceCollection.AppendEntry(pGI);
      }

      // render the collection
      const int iLitGeoCount = s_RenderGeoInstanceCollection.GetNumEntries();
      if (iLitGeoCount > 0)
      {
        VCompiledTechnique *pLastTech = NULL;
        VisSurface_cl* pLastSurface = NULL;
        m_CustomGeoInstances.EnsureSize(iLitGeoCount);
        m_CustomGeoInstances.Clear();

        for (int j=0; j < iLitGeoCount; j++)
        {
          VisStaticGeometryInstance_cl *pGI = s_RenderGeoInstanceCollection.GetEntry(j);

          GetLightShader (pLight, pGI, m_pMirror->m_eReflectionShaderMode, pLastSurface, pLastTech, pLastSurface, pTechnique);
          
          // The current technique has changed, so we have to render the previously gathered geometry.
          if (pLastTech != pTechnique)
          {
            if ((m_CustomGeoInstances.GetNumEntries() > 0) && (pLastTech != NULL) && (pLastTech->GetShaderCount() > 0))
            {
              Vision::RenderLoopHelper.RenderStaticGeometryWithShader(m_CustomGeoInstances, *pLastTech->m_Shaders.GetAt(0) );
              m_CustomGeoInstances.Clear();
            }
            pLastTech = pTechnique;
          }
          m_CustomGeoInstances.AppendEntryFast(pGI);
        }
        // Render remaining geometry
        if ((m_CustomGeoInstances.GetNumEntries() > 0) && (pLastTech != NULL) && (pLastTech->GetShaderCount() > 0))
        {
          Vision::RenderLoopHelper.RenderStaticGeometryWithShader(m_CustomGeoInstances, *pTechnique->m_Shaders.GetAt(0) );
        }

        s_RenderGeoInstanceCollection.Clear();
      }
    }
  }

  // Restore default render state
  VisRenderStates_cl::SetDepthStencilState(*VisRenderStates_cl::GetDepthStencilDefaultState());
}
void VTimeOfDayComponent::UpdateParent()
{
  IVTimeOfDay *pTimeOfDayInterface = Vision::Renderer.GetTimeOfDayHandler();
  if (pTimeOfDayInterface == NULL)
    return;

  VisObject3D_cl *pOwnerObject = (VisObject3D_cl *)m_pOwner;
  VASSERT(pOwnerObject);

  hkvVec3 vDirection(hkvNoInitialization);
  pTimeOfDayInterface->GetSunDirection(vDirection);
  vDirection.normalizeIfNotZero();

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE)
  {
    vDirection = -vDirection; 
  }
  else if(AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE)
  {
    vDirection.x = -vDirection.x;
    vDirection.y = -vDirection.y;
  }
  
  if (AttachmentType != TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE)
  {
    pOwnerObject->SetDirection(vDirection);
  }

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
  {
    // TODO (multiple renderer nodes)
    IVRendererNode *pRenderer = Vision::Renderer.GetRendererNode(0);
    float fNear, fFar;
    pRenderer->GetReferenceContext()->GetClipPlanes(fNear, fFar);
    hkvVec3 vCamPos = pRenderer->GetReferenceContext()->GetCamera()->GetPosition();

    hkvVec3 vCoronaPos = -vDirection;
    vCoronaPos *= 0.95f * fFar;
    vCoronaPos += vCamPos;
    pOwnerObject->SetPosition(vCoronaPos);
  }

  if (m_bIsLightClass)
  {
    VisLightSource_cl *pLight = (VisLightSource_cl*)m_pOwner;
    VColorRef sunColor = pTimeOfDayInterface->GetSunColor();

    bool bSwitchable = (AttachmentType == TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE);
    float fBelowHorizonMultiplier = hkvMath::pow (hkvMath::Max(-vDirection.z+0.1f, 0.0f), bSwitchable ? 1.0f : 0.1f);
    fBelowHorizonMultiplier = hkvMath::Min(1.0f, fBelowHorizonMultiplier);

    if (bSwitchable && fBelowHorizonMultiplier < 1.0f && fBelowHorizonMultiplier > 0.f)
    {
      pLight->SetColor(m_iColor);
      pLight->SetMultiplier(Intensity * (1.0f - fBelowHorizonMultiplier));
    }
    else if (AttachmentType == TIMEOFDAY_ATTACHMENT_SUNLIGHTSOURCE)
    {
      pLight->SetColor(sunColor);
      pLight->SetMultiplier(Intensity * fBelowHorizonMultiplier);
    }
    else if ((AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE) ||
             (AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE))
    {
      // TODO
      VColorRef negativeColor = V_RGBA_WHITE - sunColor;
      pLight->SetColor(negativeColor);
      pLight->SetMultiplier(Intensity * fBelowHorizonMultiplier * 0.333f);
    }  
    else if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
    {
      hkvVec3 vSunColorFloat = sunColor.ToFloat();
      float fLargestComponent = hkvMath::Max(hkvMath::Max(vSunColorFloat.x, vSunColorFloat.y), vSunColorFloat.z);
      if (fLargestComponent <= 0.0f)
        fLargestComponent = 1.0f;
      sunColor.FromFloat(vSunColorFloat * (1.0f / fLargestComponent));

      pLight->SetColor(sunColor * fBelowHorizonMultiplier);
      pLight->SetMultiplier(0.0f);
    }
  }
}
void VCoronaManager::RenderCorona (VCoronaCandidate& coronaCandidate, VTextureObject*& pTexture)
{
#ifdef SUPPORTS_CORONAS
  VCoronaComponent *pCorona = coronaCandidate.m_pCorona;
  VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext();
  VisLightSource_cl* pLight = (VisLightSource_cl*)pCorona->GetOwner();

  hkvVec3 vLightPos(hkvNoInitialization);
  pLight->GetVirtualPosition(vLightPos, pContext);
  hkvVec3 vEyePos(hkvNoInitialization);
  pContext->GetCamera()->GetPosition(vEyePos);
  hkvVec3 vDir = pContext->GetCamera()->GetDirection();

  // Corona texture
  VTextureObject *pTex = pCorona->GetCoronaTexture();
  if (pTex == NULL)
    return;

  if (pTexture != pTex)
  {
    pTexture = pTex;
    Vision::RenderLoopHelper.BindMeshTexture(pTexture,0);
  }

  // Get light color
  VColorRef color = pLight->GetColor();
  hkvVec3 vDist = vLightPos - vEyePos;
  float fEyeDist = vDir.dot(vDist);

  //determine if camera is in light cone if the light is directional
  float fDirectionalDampening = 1.0f;
  if ( pLight->GetType() == VIS_LIGHT_SPOTLIGHT && pCorona->GetOnlyVisibleInSpotLight() )
  {
    fDirectionalDampening = 0.0f;
    float fConeAngle = pLight->GetProjectionAngle();
    float fConeLength = pLight->GetRadius();
    hkvVec3 fConeDirection = pLight->GetDirection();
    fConeDirection.normalize();

    hkvVec3 vLightEyeDist = vEyePos - vLightPos;

    //#2 check if the camera is inside the angle of the cone
    float cosinusAngle = (vLightEyeDist/vLightEyeDist.getLength()).dot(fConeDirection);
    float fDegree = hkvMath::acosDeg(cosinusAngle);
    float normRadius = fDegree / (fConeAngle/2.0f);

    if (normRadius < 1.0f)
    {
      //hardcoded falloff. For better performance, we avoid sampling the projection texture here.
      const float fEpsilon = 64.0f/256.0f;
      const float fQuadFactor = 1.0f/fEpsilon - 1.0f;
      fDirectionalDampening = 1.0f / (1.0f + fQuadFactor*normRadius*normRadius);

      // scale the function so that the value is exactly 0.0 at the edge and 1.0 in the center
      fDirectionalDampening = (fDirectionalDampening - fEpsilon) / (1.0f - fEpsilon);  
    }
  }
  // Fog params
  float fFogDampening = 1.0f;
  if (pLight->GetType() != VIS_LIGHT_DIRECTED && Vision::World.IsLinearDepthFogEnabled())
  {  
    const VFogParameters &fog = Vision::World.GetFogParameters();
    float fFogStart = fog.fDepthStart;
    float fFogEnd = fog.fDepthEnd;

    float fFogFactor = (fFogEnd > fFogStart) ? ((fEyeDist - fFogStart) / (fFogEnd - fFogStart)) : 0.f;
    fFogDampening = 1.0f - hkvMath::clamp(fFogFactor, 0.0f, 1.0f);
  }

  // Get corona rotation
  float fRotation = 0.0f;
  hkvVec4 vRotation(1.0f, 0.0f, 0.0f, 1.0f);
  if (pCorona->CoronaFlags & VIS_CORONASCALE_ROTATING)
  { 
    fRotation = hkvMath::mod (fEyeDist * 0.5f, 360.f);

    vRotation.x = hkvMath::cosDeg (fRotation);
    vRotation.y = -hkvMath::sinDeg (fRotation);
    vRotation.z = -vRotation.y;
    vRotation.w = vRotation.x;
  }

  // Texture dimensions
  int iSizeX, iSizeY, depth;
  pTex->GetTextureDimensions(iSizeX, iSizeY, depth);

  hkvVec4 vScale(0.0f, 0.0f, 0.0f, 0.0f);

  int iMainWidth, iMainHeight, iWidth, iHeight;
  pContext->GetSize(iWidth, iHeight);
  VisRenderContext_cl::GetMainRenderContext()->GetSize(iMainWidth, iMainHeight);

  // Preserve texture aspect ratio
  int iTexHeight = pTex->GetTextureHeight();
  int iTexWidth = pTex->GetTextureWidth();

  // Perspective scaling
  // This scaling ensures roughly the same size on 720p as the old implementation.
  vScale.z = iTexWidth * pCorona->CoronaScaling * 0.25f;
  vScale.w = iTexHeight * pCorona->CoronaScaling * 0.25f;

  // Screen-space scaling
  // This scaling ensures roughly the same size on 720p as the old implementation.
  const float fScaleFactor = pCorona->CoronaScaling * iMainHeight / 11.0f;
  vScale.x = ((float)iTexWidth / 128.0f) * fScaleFactor * (float(iWidth) / float(iMainWidth));
  vScale.y = ((float)iTexHeight / 128.0f) * fScaleFactor * (float(iHeight) / float(iMainHeight));
  vScale.x *= 2.0f / iWidth;
  vScale.y *= 2.0f / iHeight;
  
  // Scale by visibility
  if (pCorona->CoronaFlags & VIS_CORONASCALE_VISIBLEAREA)
  {
    vScale.x *= coronaCandidate.m_fCurrentVisibility;
    vScale.y *= coronaCandidate.m_fCurrentVisibility;
    vScale.z *= coronaCandidate.m_fCurrentVisibility;
    vScale.w *= coronaCandidate.m_fCurrentVisibility;
  }

  VCompiledShaderPass* pShader = m_spCoronaTechnique->GetShader(0);
  VShaderConstantBuffer *pVertexConstBuffer = pShader->GetConstantBuffer(VSS_VertexShader);
  // xyz = worldspace position, w = 1.0 if VIS_CORONASCALE_DISTANCE is true, otherwise zero.
  pVertexConstBuffer->SetSingleParameterF("coronaPosition", vLightPos.x, vLightPos.y, vLightPos.z, (pCorona->CoronaFlags & VIS_CORONASCALE_DISTANCE) ? 1.0f : 0.0f);
  // xyz = light color, w = corona visibility.
  pVertexConstBuffer->SetSingleParameterF("coronaColor", color.r/255.0f, color.g/255.0f, color.b/255.0f, coronaCandidate.m_fCurrentVisibility * fFogDampening * fDirectionalDampening);
  // xyzw = 2x2 rotation matrix. float2x2 is not supported in shader model 2, so a float4 is used and multiplication is done manually in the shader.
  pVertexConstBuffer->SetSingleParameterF("coronaRotation", vRotation.x, vRotation.y, vRotation.z, vRotation.w);
  // xy = screen-space scaling. zw = view-space scaling.
  pVertexConstBuffer->SetSingleParameterF("coronaScale", vScale.x, vScale.y, vScale.z, vScale.w);
    
  Vision::RenderLoopHelper.RenderMeshes(pShader, VisMeshBuffer_cl::MB_PRIMTYPE_TRILIST, 0, 2, 6);
#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
}
void VTimeOfDayComponent::UpdateParent()
{
  VTimeOfDay *pTimeOfDayInterface = (VTimeOfDay*)Vision::Renderer.GetTimeOfDayHandler();
  if (pTimeOfDayInterface == NULL)
    return;

  VisObject3D_cl *pOwnerObject = (VisObject3D_cl *)m_pOwner;
  VASSERT(pOwnerObject);

  hkvVec3 vDirection(hkvNoInitialization);
  pTimeOfDayInterface->GetSunDirection(vDirection);

  // The Moon and back light direction is calculated from the Sun direction
  if (AttachmentType == TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE)
  {
    vDirection = -vDirection; 
  }
  else if(AttachmentType == TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE)
  {
    vDirection.x = -vDirection.x;
    vDirection.y = -vDirection.y;
  }
  
  if (AttachmentType != TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE)
  {
    pOwnerObject->SetDirection(vDirection);
  }

  if (AttachmentType == TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE)
  {
    // TODO (multiple renderer nodes)
    IVRendererNode *pRenderer = Vision::Renderer.GetRendererNode(0);
    float fNear, fFar;
    pRenderer->GetReferenceContext()->GetClipPlanes(fNear, fFar);
    hkvVec3 vCamPos = pRenderer->GetReferenceContext()->GetCamera()->GetPosition();

    hkvVec3 vCoronaPos = -vDirection;
    vCoronaPos *= 0.95f * fFar;
    vCoronaPos += vCamPos;
    pOwnerObject->SetPosition(vCoronaPos);
  }

  // Set the color and intensity of the light
  if (m_bIsLightClass)
  {
    VisLightSource_cl *pLight = (VisLightSource_cl*)m_pOwner;
    VColorRef color;
    float intensity = 0.0f;

    switch (AttachmentType)
    {
    case TIMEOFDAY_ATTACHMENT_ENABLEDATNIGHTLIGHTSOURCE:
      {
        color = m_iColor;
        const float fMarginNearHorizon = 0.1f; //10% - Margin above the horizon to switch lights ON/OFF
        const float fBelowHorizonMultiplier = hkvMath::Max(-vDirection.z + fMarginNearHorizon, 0.0f);
        intensity = 1.0f - hkvMath::Min(1.0f, fBelowHorizonMultiplier);
        break;
      }
    case TIMEOFDAY_ATTACHMENT_CORONALIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetSunColor();
        hkvVec3 vSunColorFloat = color.ToFloat();
        float fLargestComponent = hkvMath::Max(hkvMath::Max(vSunColorFloat.x, vSunColorFloat.y), vSunColorFloat.z);
        if (fLargestComponent > 0.0f)
        {
          color.FromFloat(vSunColorFloat / fLargestComponent);
        }      
        intensity = 0.0f;
        break;
      }
    case TIMEOFDAY_ATTACHMENT_SUNLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetSunColor();
        intensity = pTimeOfDayInterface->GetSunIntensity();
        break;
      }
    case TIMEOFDAY_ATTACHMENT_SUNBACKLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetBackLightColor();
        intensity = pTimeOfDayInterface->GetBackLightIntensity();
        break;
      }
    case TIMEOFDAY_ATTACHMENT_MOONLIGHTSOURCE:
      {
        color = pTimeOfDayInterface->GetMoonColor();
        intensity = pTimeOfDayInterface->GetMoonIntensity();
        break;
      }
    default:
      VASSERT_MSG(0,"Unknown time of day attachment type");
    }

    pLight->SetColor(color);
    pLight->SetMultiplier(intensity * Intensity);    
  }
}
void VFakeSpecularGenerator::OnDoRenderLoop(void *pUserData)
{
  VFrustumMeshHelper::UpdateMeshBuffer(m_spMeshBuffer, Vision::Contexts.GetCurrentContext(), VFrustumMeshHelper::IN_WORLD_SPACE);

  Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, VColorRef(0, 0, 0, 0));

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

  const VisLightSrcCollection_cl* pLights = pContext->GetVisibilityCollector()->GetVisibleLights();

  Vision::RenderLoopHelper.BeginMeshRendering();
  Vision::RenderLoopHelper.ResetMeshStreams();
  Vision::RenderLoopHelper.AddMeshStreams(m_spMeshBuffer, m_spShader->GetStreamMask () | VERTEX_STREAM_INDEXBUFFER);
  for(unsigned int iLightIndex = 0; iLightIndex < pLights->GetNumEntries(); iLightIndex++)
  {
    VisLightSource_cl* pLight = pLights->GetEntry(iLightIndex);

    if((pLight->GetVisibleBitmask() & pContext->GetRenderFilterMask()) == 0)
      continue;

    if(!pLight->GetUseSpecular())
      continue;

    hkvVec4 vDirection;

    hkvVec3 vLightPositionRel = pLight->GetPosition() - pContext->GetCamera()->GetPosition();
    hkvVec3 vLightDirection = pLight->GetDirection();

    float fAttenuation = 1;
    switch(pLight->GetType())
    {
    case VIS_LIGHT_DIRECTED:
      vDirection = vLightDirection.getAsVec4(1.0f);
      break;

    case VIS_LIGHT_SPOTLIGHT:
      {
        vDirection = vLightDirection.getAsVec4(1.0f);

        float fAngle = vLightPositionRel.getAngleBetween(-vLightDirection);
        float fConeAngle = pLight->GetProjectionAngle();
        fAttenuation = hkvMath::clamp((fConeAngle - fAngle) / fConeAngle, 0.0f, 1.0f);

        float fDistance = vLightPositionRel.getLength();
        float fRadius = pLight->GetRadius();
        fAttenuation *= hkvMath::clamp((fRadius - fDistance) / fRadius, 0.0f, 1.0f);
      }
      break;

    case VIS_LIGHT_POINT:
      vDirection = (-vLightPositionRel).getNormalized().getAsVec4(1.0f);
      float fDistance = vLightPositionRel.getLength();
      float fRadius = pLight->GetRadius();
      fAttenuation = hkvMath::clamp((fRadius - fDistance) / fRadius, 0.0f, 1.0f);
      break;
    }

    hkvVec4 vColor = pLight->GetColor().getAsVec4() * pLight->GetMultiplier() * fAttenuation;

    hkvVec4 vParams(m_fSpecularPower, 0, 0, 0);

    m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fLightDirection", vDirection.data);
    m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fLightColor", vColor.data);
    m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fParams", vParams.data);

    Vision::RenderLoopHelper.RenderMeshes(m_spShader, VisMeshBuffer_cl::MB_PRIMTYPE_INDEXED_TRILIST, 0, 2, 6);
  }
  Vision::RenderLoopHelper.EndMeshRendering();

  // Trigger pre-screenmask render hook to make the attached cubemap handle flip and blur the cubemap target
  VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook, VRH_PRE_SCREENMASKS);
  Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data);
}